インターフェイスは実行時にのみ型チェックされるため、Invokeinterface は異なります。仮想メソッドを使用すると、型がメソッドが定義されているクラスのサブタイプであることを静的に判断できます。インターフェイスの場合、値の実行時の型を知らずに、値がそのインターフェイスを実装する型を持っているかどうかを確実に知ることは不可能です。
次の疑似コードを検討してください (これは Java では許可されていませんが、JVM では同等のバイトコードが許可されていることに注意してください)。
class A
class B extends A implements Foo
A a = new B()
a.fooMethod()
静的型 A は Foo を実装していませんが、実際のランタイム型 B は実装しているため、 a が Foo を実装しているかどうかを静的に知る方法はありません。
編集: 上記の例は Java コンパイラによって拒否されますが、JVM では拒否されません。JVM がコンパイラと同じ規則を適用しないのはなぜかと思うかもしれません。違いは、JVM にはローカル変数に関するソース レベルの型情報がないことです。Java で許可されている次の例を考えてみましょう。
class A
class B extends A implements Foo
class C extends A implements Foo
Foo x = null;
if (whatever) {
x = new B();
} else {
x = new C();
}
x.fooMethod();
JVM は x の意図した型を認識していないため (stackmaptables は後で導入されました)、x の型を であると推測しますがA
、これは を実装していませんFoo
。したがって、検証時にインターフェイスを静的にチェックしようとすると、有効な Java コードが拒否されます。実行可能な唯一の解決策は、インターフェースをタイプチェックしないことです。
インターフェースを安全にチェックするために、JVM は「Foo も実装する A のサブクラス」のような型を推論できなければなりません。したがって、デザイナーがこのルートに行かなかったのは理にかなっています。
PS Invokespecial は、コンストラクターだけでなく、プライベート メソッドやスーパー メソッドの呼び出しにも使用されます。呼び出されたメソッドは、ターゲットの実行時のタイプによって変化するのではなく、ロード時に認識されるため、元は最適化として別の命令であった可能性が最も高いです。実際、もともとは invokenonvirtual と呼ばれていました。