2013-07-24 83 views
1

在Java中,我們不能在繼承類時指定private,protected或public。例如下面的代碼在Java中是不可能的。爲什麼?爲什麼Java沒有基於訪問指定符的繼承

class A { 
    public void display() { 
     //Some implementation of display logic. 
    } 
} 

class B extends **protected** A 
{ 
    public void show() { 
     display(); 
     //some more logic. 
    } 
} 

B obj = new B(); 
obj.show(); 

我不想要obj.display()並需要隱藏它的實現從外部世界。在C++中,我們可以使用基於訪問修飾符的繼承,但在java中不能。我的問題是,如果我們想隱藏實現,我們如何實現這一目標?

爲什麼在Java中採用此架構決策在繼承期間刪除訪問修飾符時,使用它有什麼危害?

+3

什麼是你想實現與訪問修飾符爲基類? – jlordo

+0

是的,更新了問題。 –

+0

我認爲他是問爲什麼......在我看來,Ankit,Java被設計成純粹的OO語言..而C++也被設計爲支持OO範式。所以這裏Java的人認爲這些在C++中的東西可以使事情更復雜,所以他們離開它。 所以,如果你仍然有像這樣的probs意味着,很明顯,你沒有完全轉向Java。你正試圖在Java中實現C++。這不好。 所以我建議你重新考慮你目前的概率的OO設計。 – Dreamer

回答

1

C++提供了允許物理繼承作爲類的實現細節的一部分的功能。

這部分C++被設計爲之前 Barbara Liskov介紹了現在被稱爲Liskov substitution principle的內容。爲了滿足Liskov替換原則,無論使用超類的實例,也可以使用子類的實例。在你的情況下,你可以將B傳給一個預期爲A的方法。引入這個原理後,Java被設計爲。在Java中,繼承的物理機制僅用於從其超類中邏輯上繼承的類。要使用類的實現,但不使用它的接口,可以使用委派。

從Stroustrup的「C++的設計和演化」:

「爲基類的私有/公共區別通過五年左右[星達,1986] [里氏早在實現繼承與接口繼承辯論,1987)如果你只想繼承一個實現,你可以在C++中使用私有派生,派生類的用戶可以訪問基類提供的接口,私有派生爲基礎留下一個實現細節;甚至基類的公共成員不可訪問,除非通過爲派生類明確提供的接口。「

+0

是的,我同意但爲什麼這個架構決策是針對Java的 –

+0

其中一個原因(如上所述)是它會打破Liskov替換原則。 –

+0

@AnkitZalani - 挖掘一下這一點,參見上面的編輯。 –

2

請注意,您不能減少方法或字段的可見性,因爲它會將子類傳遞給需要超類的方法。但是,您可以增加它。

讓我們來看一個例子:

public static void displayFromA(A a){ 
    a.display(); 
} 

由於B延伸A我們可以通過B了這一點。如果Bdisplay(方法的可見性降低,則此方法無效。這將打破Liskov替代原則的前提,正式地說,如果q(x)是一個方法調用display(的能力的真值,則q(x)將作爲A的一個實例持有x,但不一定如果x是A的子類型

+0

請看看,我已經更新了這個問題。 –

+0

@AnkitZalani你不能這樣做會打破超類型兼容性,以防某些方法需要'A'來運行'display('on,但你通過了它B.你只能增加可見性。 – hexafraction

0

防止訪問底層顯示器()的一種方法是覆蓋它。例如在你的B類中:

@Override 
public void display() { 
    throw new UnsupportedOperationException("Do not use B.display(), please use B.show() instead"); 
} 

而且,在B中,例如,在show()中,改爲調用super.display()。

但是,這將在運行時捕獲,而不是在編譯期間捕獲。添加一些javadoc並希望他們閱讀它們。 :-)

我不知道添加類似於@NeverCallMe註釋的方法,它會在編譯時被捕獲。任何人都知道這個訣竅?

(補充)順便說一句,我同意Java的設計師和其他答案,這是你通常不應該做的適當的面向對象,Liskov和所有這些。但是,這是一種有點瘋狂的方式來做你想做的事。

0

如果您想隱藏每個人的信息,沒有理由讓B班與A班有「IS-A」關係。

如果你只是想重新使用從A類的代碼,你可以有B類保鮮膜的實例,並委託給它,像這樣:

class B{ 
    //this is our delegate to A 
    private A myA = new A(); 

    public void show() { 
     myA.display(); 
     //some more logic. 
    } 
} 

B obj = new B(); 
obj.show();