2011-03-05 108 views

回答

10

我會嘗試將其他答案的想法納入到單個答案中。

首先,讓我們來看看代碼中發生了什麼。

一看代碼

One類有一個包私人foo方法:

class One { 
    // The lack of an access modifier means the method is package-private. 
    void foo() { } 
} 

Two類的子類的One類和foo方法重寫,但有訪問修飾符private

class Two extends One { 
    // The "private" modifier is added in this class. 
    private void foo() { /* more code here */ } 
} 

問題

Java語言不允許子類,以減少在子類中的方法,字段或類的可見性,因此,Two類減少foo方法的能見度不合法。

爲什麼要降低可見性是一個問題?

考慮我們要使用的One類情況:

class AnotherClass { 
    public void someMethod() { 
    One obj = new One(); 
    obj.foo(); // This is perfectly valid. 
    } 
} 

這裏,調用foo方法上One實例有效。 (假設AnotherClass類在同一個包中One類)。

現在,如果我們是來實例化對象Two,並將其放置在型Oneobj變量?

class AnotherClass { 
    public void someMethod() { 
    One obj = new Two(); 
    obj.foo(); // Wait a second, here... 
    } 
} 

Two.foo方法是私有的,然而,One.foo方法將允許訪問方法。我們在這裏遇到了問題。

因此,考慮繼承時允許降低可見性沒有多大意義。

鏈接

+0

+1作爲寫過其他答案之一的人,這是一篇很好的總結,寫得很好。感謝您將它們放在一起! – templatetypedef

+0

非常精確,重點突出。 –

1

此代碼的問題在於,如果它是合法的,那麼如果您通過One基類間接訪問它,Java將無法尊重private修飾符foo。例如,如果我寫

One obj = new Two(); 
obj.foo(); 

那麼我們就會有麻煩,因爲我們會被調用private方法Twofoo間接,當編譯器檢查它着眼於One以確定線路obj.foo()自如果foo可訪問,則不在Two。這樣做的原因是,編譯器不能總是分不清什麼obj可以在被人指指點點 - 如果,例如,我喜歡寫東西

One obj = Math.random() < 0.5? new One() : new Two(); 
obj.foo(); 

那麼編譯器無法知道是否在Oneobj點或一個Two。因此,在檢查訪問說明符時,它會遵循One。如果我們確實允許在Two中標記foo private,那麼編譯器會錯誤地允許我們通過obj(它的類型爲One)調用它,繞過保證只有對象本身可以調用private方法。

+0

真正的問題是在Java中不允許降低可見性。即使第一個方法被保護,第二個包爲私有,編譯器也可以編譯,但是不允許聲明。 – bestsss

+0

@ bestsss-是的,這是真的,但這個決定背後的推理是對上述邏輯的擴展。 – templatetypedef

0

它會破壞多態性。

如果你有一個Two實例存儲在一個Two變量中,那麼foo不能被調用是有意義的。但是,如果您將One實例存儲在One變量中,那麼您只知道One。但是,一個人擁有公共福利,這可以被稱爲。這將是一個不一致,而且會很奇怪。

0

因爲繼承是的關係。任何人都可以通過參考指的Two一個實例One

One v = new Two(); 

什麼會的程序做,如果你呼籲V基準foo的方法是什麼?你打破了One的公共契約,保證One的每個實例都有一個(這裏是封裝保護的)foo方法。這就是編譯器禁止它的原因。

1

給出的答案給你技術上的解釋,爲什麼你不能一個接一個的擴展。我想給你一個理解,爲什麼這是不可能的,因爲面向對象的模式,而不是由於語言本身。

通常,第一類是帶有其訪問器的類的一般定義,即方法到外部世界。擴展這個類的子類必須爲外部世界提供相同的訪問者。兩個在你的例子中擴展一個,這意味着,Two提供了和One一樣的外部世界的訪問器。如果您要更改One的訪問器的可見性,則外部世界將無法再訪問您的類,因爲它們習慣使用類型爲One的對象進行訪問。

相關問題