2016-04-24 5 views
0

問題が発生しました。継承時に、ベースコンストラクタが仮想メソッドを呼び出すと、そのクラスがDerviedでDerviedメソッドを呼び出すのはなぜですか?

public class Dervied extends Base { 
    private String name = "dervied"; 
    public Dervied() { 
     System.out.println(this.getClass().toString()); 
     this.tellName(); 
    } 
    public void tellName() { 
     System.out.println("Dervied tell name: " + name); 
    } 
    public static void main(String[] args) { 
     Base base = new Dervied(); 
    } 
} 

class Base { 
    private String name = "base"; 
    public Base() { 
     System.out.println(this.getClass().toString()); 
     this.tellName(); 
    } 
    public void tellName() { 
     System.out.println("Base tell name: " + name); 
    } 
} 

結果は次のとおりです:

class Dervied 
Dervied tell name: null 
class Dervied 
Dervied tell name: dervied 

しかし、なぜ期待通りに以下のコードは、実行されませんか?環境はjdk1.8.0_60とWindows 10です。new Dervied()メソッドをDervied()に実行し、ベースコンストラクタBase()を呼び出します。しかし、Base()の印刷クラスはなぜDerviedですか?そして、this.tellName()は、Derviedクラスのメソッドを多相として呼び出しますか?

+0

フィールドは多型ではありません。 – Savior

答えて

2

これは、コンストラクタから仮想メソッドを決して呼び出してはいけない理由です。コンストラクタを実行すると、さまざまな段階があります。最初に、基本クラスコンストラクターが実行され、次に派生クラスコンストラクターが実行されます。

したがって、仮想呼び出しはコンストラクタがあるステージに依存し、まだ存在しないオブジェクトに対してメソッドを呼び出すことになります。

これは、基本クラスコンストラクターが実行され、DerivedクラスオブジェクトのtellName()を呼び出すため、Derivedの 'name'インスタンス変数がまだ初期化されていないためにnullが表示されるのを示します。ここで

はジョシュアブロッホの効果的なJavaから関連の引用である - 第2版:

スーパークラスのコンストラクタは、サブクラスのコンストラクタの前に実行されるので、 サブクラスのコンストラクタを持って前に、サブクラスで オーバーライドするメソッドが呼び出されます走るオーバーライドするメソッドがサブクラスコンストラクタによって実行された の初期化に依存する場合、メソッドは が期待どおりに動作しません。

関連する問題