2011-06-24 14 views
1

Javaでの隠蔽の仕組みを理解したいと思います。 は、だから私は、私がNullPointerExceptionで光栄取得コンパイルした場合は、コードJavaの隠蔽/シャドウイングメンバ変数についての質問

public class A{ 
    protected SomeClass member; 
    public A(SomeClass member){ 
     this.member = member; 
    } 
} 

public class B extends A{ 
    protected SomeClass member; 
    public B(SomeClass member){ 
     super(member); 
    } 
    public static void main(String[] args){ 
     SomeClass sc = new SomeClass(); 
     B b = new B(sc); 
     System.out.println(b.member.toString()); 
    } 
} 

次したと仮定することができます。私はそれがsc.toString()の出力であると思った。

私は

public class A{ 
    protected SomeClass member; 
    public A(SomeClass member){ 
     setMember(member); 
    } 
    public void setMember(SomeClass sc){ 
     this.member = sc; 
    } 

} 

public class B extends A{ 
    protected SomeClass member; 
    public B(SomeClass member){ 
     super(member); 
    } 
    public void setMember(SomeClass sc){ 
     this.member = sc; 
    } 
    //...main 
} 

にこのコードを変更し、期待どおりに出力を得る... Bの OK setMemberので、私はこの方法でこれを説明することができるから1を上書きします。 少し遊んで、BからsetMemberを削除して、NullPointerExceptionを取り戻しました。しかし、それは再びコンパイルし、私は

public class A{ 
    protected SomeClass member; 
    public A(SomeClass member){ 
     setMember(member); 
    } 
    public void setMember(SomeClass sc){ 
     member = sc; 
    } 

} 

にAのコードを変更した場合、工assメンバーの2つのインスタンスが実際に存在しているように私には思える私に出力を提供します...しかし、2つのインスタンスがある場合、何がシャドーイング意味しますか?後者の場合にだけ隠れることは有用でしょうか?

+0

最初の例は 'b'にメンバー' sc'がないため、コンパイルされません。これは 'System.out.println(b.sc.toString());')で失敗します。あなたのコンパイラがこれを受け入れるなら、それは壊れています。 –

答えて

3

最初のコードサンプルの最後の行がb.member.toString()であると仮定します。

"member"という名前のメンバ変数が2つあり、両方の例では、this.memberへの割り当てが1つだけ呼び出されているため、そのうちの1つだけが設定されています。最初の例を修正するには、通常

public B(SomeClass member) {   
    super(member); 
    this.member = member; 
} 

言うだろうしかし、私はあなたがすでにそれを理解し、言語がこのように設計されている理由は本当に求めていると思います。これは、スーパークラス実装のカプセル化と関係しています。スーパークラスの作成者は、サブクラスを破棄することなくそれを書き換えることができ、その逆も可能です。 Bの "作者"の著者が周りに持っているのが良いことになるので、B.memberが最初に来たとしたら、Aの作者は同じ考えを持っていたと想像してください。

このシステムは完璧ではありませんが、2番目の例ではその理由を示しています。 B.setMember()が最初に来て、Aの新しいバージョンがA.setMember()を導入した場合、Aの作成者は、オーバーライドするB.setMember()メソッドを予測できず、結果としてA.memberが決して初期化されないように、コンストラクタを表示することができません。 C#はこの種のものをキャッチするために "オーバーライド"キーワードを導入しました。Javaはそれを "@overrides"として借用しましたが、その注釈はJavaでは忠実ではありません。

+0

はいshure私は私のメインメソッドでmember.toString()を意味 - それはちょうどタイプミス;) しかし、この回答はとにかく有用だった –