インタフェースタイプ参照Objectクラスを呼び出す方法
まず、このコードを見てみましょう.
Javaを習ったばかりの頃、変数iはInterfaceTestタイプで、InterfaceTestにはtoString()メソッドは宣言されていませんが、なぜコンパイルできるのでしょうか?
『The Java Programming Language』では次のように紹介されています.
You can invoke any of the Object methods using a reference of an interface type because no matter what interfaces the object implements, it is always an Object and so has those methods. In fact, any interface that does not extend some other interface implicitly has members matching each of the public methods of Object (unless the interface explicitly overrides them).
ここでいう理由は,インタフェースに暗黙的にObject定義を持つメソッドメンバである.
「Java言語規範」には似たような言い方があります.
If an interface has no direct superinterfaces, then the interface implicitly declares a public abstract member method m with signature s, return type r, and throws clause t corresponding to each public instance method m with signature s, return type r, and throws clause t declared in Object, unless a method with the same signature, same return type, and a compatible throws clause is explicitly declared by the interface. It is a compile-time error if the interface explicitly declares such a method m in the case where m is declared to be final in Object.
ここでも暗黙的な声明です.
暗黙的な宣言なら、コンパイラがインタフェースに追加したと思います.仮想マシンがこれらのメソッドを呼び出すと、マルチステート現象が発生し、オブジェクトの実際のタイプに基づいてこれらのメソッドを検索します.しかし、実際にSUNのjdkはそうではない.
逆アセンブリでmainメソッドの内容は次のとおりです.
0: new #5;//class Test 3: dup 4: invokespecial #6;//Method "":()V 7: astore_1 8: aload_1 9: invokevirtual #7;//Method java/lang/Object.toString:()Ljava/lang/String; 12: pop 13: aload_1 14: invokeinterface #8, 1;//InterfaceMethod InterfaceTest.test:()V 19: return
ここではinvokevirtualで呼び出されるObjectで定義されたメソッドを直接使用することに注意してください.つまりコンパイラはjava言語規範のように働いていません.インタフェースタイプが変数を参照してObjectクラスのメソッドを呼び出す場合、コンパイラはinvokevirtualを直接使用して処理します.このようにしても、まず、意味的な表現は影響を受けません.次に、invokevirtualはinvokeinterfaceよりも優れた性能を有している.invokevirtualはインデックスに基づいて直接方法を位置決めすることができるが、invokeinterfaceは隣接して比較して方法を決定する以外に特に良い方法はないようだ.
interface InterfaceTest{
void test();
}
public class Test implements InterfaceTest{
public void test(){
System.out.println("test");
}
public static void main(String[] args){
InterfaceTest i = new Test();
i.toString();
i.test();
}
}
Javaを習ったばかりの頃、変数iはInterfaceTestタイプで、InterfaceTestにはtoString()メソッドは宣言されていませんが、なぜコンパイルできるのでしょうか?
『The Java Programming Language』では次のように紹介されています.
You can invoke any of the Object methods using a reference of an interface type because no matter what interfaces the object implements, it is always an Object and so has those methods. In fact, any interface that does not extend some other interface implicitly has members matching each of the public methods of Object (unless the interface explicitly overrides them).
ここでいう理由は,インタフェースに暗黙的にObject定義を持つメソッドメンバである.
「Java言語規範」には似たような言い方があります.
If an interface has no direct superinterfaces, then the interface implicitly declares a public abstract member method m with signature s, return type r, and throws clause t corresponding to each public instance method m with signature s, return type r, and throws clause t declared in Object, unless a method with the same signature, same return type, and a compatible throws clause is explicitly declared by the interface. It is a compile-time error if the interface explicitly declares such a method m in the case where m is declared to be final in Object.
ここでも暗黙的な声明です.
暗黙的な宣言なら、コンパイラがインタフェースに追加したと思います.仮想マシンがこれらのメソッドを呼び出すと、マルチステート現象が発生し、オブジェクトの実際のタイプに基づいてこれらのメソッドを検索します.しかし、実際にSUNのjdkはそうではない.
逆アセンブリでmainメソッドの内容は次のとおりです.
0: new #5;//class Test 3: dup 4: invokespecial #6;//Method "
ここではinvokevirtualで呼び出されるObjectで定義されたメソッドを直接使用することに注意してください.つまりコンパイラはjava言語規範のように働いていません.インタフェースタイプが変数を参照してObjectクラスのメソッドを呼び出す場合、コンパイラはinvokevirtualを直接使用して処理します.このようにしても、まず、意味的な表現は影響を受けません.次に、invokevirtualはinvokeinterfaceよりも優れた性能を有している.invokevirtualはインデックスに基づいて直接方法を位置決めすることができるが、invokeinterfaceは隣接して比較して方法を決定する以外に特に良い方法はないようだ.