2011-07-21 25 views
2

この単純なプログラムの出力はThis is baseです。メソッドバインディングの混乱

public class mainApp{ 
    private void func(){ 
     System.out.println("This is base"); 
    } 

    public static void main(String[] args){ 
     mainApp newObj = new derived(); 
     newObj.func(); 
    } 
} 

class derived extends mainApp{ 
    public void func(){ 
     System.out.println("This is derived"); 
    } 
} 
  • 私の質問私達はこのラインmainApp newObj = new derived();を使用しているときである私たちが実際にのオブジェクトを作成していないが、基本クラスmainAppですの参照を使用してクラスを派生。だから、オブジェクトを使ってメソッドを呼び出すと、派生クラスからメソッドを取得できないのですか?なぜ私は基本クラスからメソッドを取得します。このラインを使用

  • mainApp newObj = new derived();は、我々は、mainAppですの基準を使用しているか、我々は、派生クラスのオブジェクトを操作しています。どちらが正しいか?

答えて

8

基本クラスのメソッドを取得する理由は、基本クラスのバージョンfuncprivateと宣言されているため、Javaではプライベートメソッドをサブクラスでオーバーライドできないためです。つまり、基底クラスを拡張し、基本クラスのプライベートメンバ関数と同じ名前のプライベートメンバ関数に名前を付けることにした場合、誤って基本クラスのメンバ関数の動作を変更することはありません。あなたは確かにタイプderivedのオブジェクトを操作しているが、参照は、静的funcmainAppプライベート方法funcではなくderivedでパブリックメソッドfuncを呼び出すように解釈されて呼び出し、mainAppとして型指定されているため。 dの静的な型が今derivedあるとfuncの呼び出しは異なる意味を持っているので、

derived d = new derived(); 
d.func(); 

修正これを読むためにコードを変更します。

JVMバイトコードレベルでは、プライベートメンバー関数の呼び出しに使用される命令はinvokespecialですが、オーバーライド可能な通常のメンバー関数を呼び出すための命令はinvokevirtualです。 2つは全く異なるセマンティクスを持っています。 invokespecialは現在のクラス(またはコンストラクタのようなもののための基本クラス)を探し始めますが、invokevirtualは実行時にオブジェクトの型に対応するクラスを探します。

+0

うわー、優秀な答えと私はパンチに私を打つ。 @iamcreasy [Java and Polymorphism](http://home.cogeco.ca/~ve3ll/jatutor5.htm)であなたの問題に関する混乱のシュラウドを解消するために少し読んでください。 – Grambot

+0

私はJavaの静的型と動的型の区別に慣れていません!私はこれを見て実際にはかなり驚いていました。私はC++を最初に学んだことが良いことです。 :-) – templatetypedef

+0

@templatetypedefしたがって、参照の後にドット表記法を使用するときは、その参照が指しているオブジェクトに関係なく、その特定の参照のメソッドを使用します。それが正しいか? & "参照は静的に型指定されています"という意味ですか? –

0

あなたはderivedクラスで作業しています。そのオブジェクトへの参照はmainAppです。つまり、他の人はmainAppと見なしますが、派生クラスとして実装されています。