2011-06-24 33 views
1

我想了解如何在Java中隱藏工作。 所以,讓我們假設你有下面的代碼關於在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()); 
    } 
} 

如果我編譯我得到一個NullPointerException異常榮幸。我認爲這將是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的確定setMember重寫從A一個這樣我就可以這樣解釋。 我玩了一下,並從B中刪除了setMember以獲取返回NullPointerException。但它再次編譯並給了我輸出,如果我改變A的代碼以

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

} 

在我看來,有其實SomeClass的成員的兩個實例...但拿什麼陰影,如果有兩個實例?第二種情況只隱藏有用嗎?

+0

你的第一個例子不會編譯,因爲'b'沒有'sc'成員。它在'System.out.println(b.sc.toString());'失敗。如果你的編譯器接受這個,它就壞掉了。 –

回答

3

我打算假設你的意思是第一個代碼示例的最後一行是b.member.toString()

有兩個名爲「member」的成員變量,在這兩個示例中只有其中一個被設置,因爲只調用了一個賦值爲this.member。要解決的第一個例子,你通常會說

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

但是我想你已經明白這一點,實際上是在問,爲什麼語言是這樣設計的。它與超類實現的封裝有關。超類的作者應該能夠在不破壞子類的情況下重寫它,反之亦然。想象一下,如果B.member出現在第一位,因爲B的作者雖然「成員」會有好處,但後來A的作者也有同樣的想法。

然而,這個系統並不完美,你的第二個例子顯示了原因。如果B.setMember()先出現,然後A的更高版本引入A.setMember(),那麼A的作者可能無法預測重寫的B.setMember()方法,並按照展示的方式編寫構造函數,結果A.member從不初始化。 C#引入了「overrides」關鍵字來捕捉這類事情,Java將它作爲「@overrides」借用,但是這種註釋在Java中並不瘋狂,因此效率不高。

+0

是的舒爾我的意思member.toString()在我的主要方法 - 這只是一個錯字;) 但這個答案是有幫助的反正 –