[#0 x 000 C]ダウンシフトの必要性とダイナミックバインドの詳細
[#0 x 009]では、「staticメソッドとfinalメソッド(finalはprivateを含む)のほか、Javaは他のすべてのメソッドに対してdynamic bindingを採用している」(P 151,Chapter 8,Thinking in Java,Fourth Edition)と述べていますが、以下の例はちょっと驚くかもしれません(adapted from Chapter 8,Thinking in Java,Fourth Edition):
本来,x.f()は動的バインディングによってMoreUsefulのf()メソッドを正しく呼び出すことができるが,なぜx.g()はだめなのか.本当に「staticメソッドとfinalメソッド(finalはprivateを含む)のほかに、Javaは他の「すべて」のメソッドに対してdynamic bindingを採用していますか?それとも上書き方法だけを動的にバインドしますか?
ここでは、ダイナミックバインドの詳細について説明します.もちろん、確かに「staticメソッドとfinalメソッド(finalはprivateを含む)のほか、Javaは他のすべてのメソッドにdynamic bindingを採用している」が、ダイナミックバインドを使用する前にコンパイラは他の作業をしていたが、これらの作業が、上面コードの結果をもたらした原因である.
Javaのメソッド呼び出しプロシージャ:
->コンパイラリファレンス(x)の宣言タイプ(Useful)とメソッド名(g()を表示します.
-->宣言タイプによってメソッドのリストを見つけます.
------>メソッド名がメソッドリストにない場合、コンパイラは(g()がUsefulのメソッドリストにないのでエラー)を報告します.
------>メソッド名がメソッドリストにある場合は、次の手順に進みます.
->コンパイラはメソッドのパラメータリストを表示し、パラメータメソッド署名を取得します.
-->メソッドがprivate、static、final、またはコンストラクタの場合、コンパイラはそのメソッドを呼び出すことを決定することができます(これは静的バインドです).
-->上記でない場合は、ダイナミックバインドを使用します.
x.g()エラーは、ダイナミックバインドを使用する前のメソッド名チェックが失敗したためであることがわかります.この観点から,動的バインドは確かに上書き法にのみ適用されるようである.
動的バインドが使用できないため、x.g()メソッドを正しく呼び出すには、下への移行(MoreUseful)x)が必要です.ここでxは実際のMoreUsefulオブジェクト(すなわち、アップコンバートによって得られる)を指し示さなければならない.Useful x=new Useful()の場合、(MoreUseful)x)はエラーをコンパイルする.
//@file RTTI.java
//RTTI: Run-Time Type Identification
class Useful
{
public void f() {System.out.println("Useful.f()");}
}
class MoreUseful extends Useful
{
public void f() {System.out.println("MoreUseful.f()");}
public void g() {System.out.println("MoreUseful.g()");}
}
public class RTTI
{
public static void main(String[] args)
{
Useful x = new MoreUseful();
x.f();
//x.g();// :
((MoreUseful)x).g(); // Downcast/RTTI
}
}
//output:
/*
MoreUseful.f()
MoreUseful.g()
*/
本来,x.f()は動的バインディングによってMoreUsefulのf()メソッドを正しく呼び出すことができるが,なぜx.g()はだめなのか.本当に「staticメソッドとfinalメソッド(finalはprivateを含む)のほかに、Javaは他の「すべて」のメソッドに対してdynamic bindingを採用していますか?それとも上書き方法だけを動的にバインドしますか?
ここでは、ダイナミックバインドの詳細について説明します.もちろん、確かに「staticメソッドとfinalメソッド(finalはprivateを含む)のほか、Javaは他のすべてのメソッドにdynamic bindingを採用している」が、ダイナミックバインドを使用する前にコンパイラは他の作業をしていたが、これらの作業が、上面コードの結果をもたらした原因である.
Javaのメソッド呼び出しプロシージャ:
->コンパイラリファレンス(x)の宣言タイプ(Useful)とメソッド名(g()を表示します.
-->宣言タイプによってメソッドのリストを見つけます.
------>メソッド名がメソッドリストにない場合、コンパイラは(g()がUsefulのメソッドリストにないのでエラー)を報告します.
------>メソッド名がメソッドリストにある場合は、次の手順に進みます.
->コンパイラはメソッドのパラメータリストを表示し、パラメータメソッド署名を取得します.
-->メソッドがprivate、static、final、またはコンストラクタの場合、コンパイラはそのメソッドを呼び出すことを決定することができます(これは静的バインドです).
-->上記でない場合は、ダイナミックバインドを使用します.
x.g()エラーは、ダイナミックバインドを使用する前のメソッド名チェックが失敗したためであることがわかります.この観点から,動的バインドは確かに上書き法にのみ適用されるようである.
動的バインドが使用できないため、x.g()メソッドを正しく呼び出すには、下への移行(MoreUseful)x)が必要です.ここでxは実際のMoreUsefulオブジェクト(すなわち、アップコンバートによって得られる)を指し示さなければならない.Useful x=new Useful()の場合、(MoreUseful)x)はエラーをコンパイルする.