class One {
void foo() { }
}
class Two extends One {
private void foo() { /* more code here */ }
}
爲什麼上面的代碼片段錯了?爲什麼不能用私有擴展類方法重寫基類方法?
class One {
void foo() { }
}
class Two extends One {
private void foo() { /* more code here */ }
}
爲什麼上面的代碼片段錯了?爲什麼不能用私有擴展類方法重寫基類方法?
我會嘗試將其他答案的想法納入到單個答案中。
首先,讓我們來看看代碼中發生了什麼。
一看代碼
的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
,並將其放置在型One
的obj
變量?
class AnotherClass {
public void someMethod() {
One obj = new Two();
obj.foo(); // Wait a second, here...
}
}
的Two.foo
方法是私有的,然而,One.foo
方法將允許訪問方法。我們在這裏遇到了問題。
因此,考慮繼承時允許降低可見性沒有多大意義。
鏈接
+1作爲寫過其他答案之一的人,這是一篇很好的總結,寫得很好。感謝您將它們放在一起! – templatetypedef
非常精確,重點突出。 –
此代碼的問題在於,如果它是合法的,那麼如果您通過One
基類間接訪問它,Java將無法尊重private
修飾符foo
。例如,如果我寫
One obj = new Two();
obj.foo();
那麼我們就會有麻煩,因爲我們會被調用private
方法Two
foo
間接,當編譯器檢查它着眼於One
以確定線路obj.foo()
自如果foo
可訪問,則不在Two
。這樣做的原因是,編譯器不能總是分不清什麼obj
可以在被人指指點點 - 如果,例如,我喜歡寫東西
One obj = Math.random() < 0.5? new One() : new Two();
obj.foo();
那麼編譯器無法知道是否在One
obj
點或一個Two
。因此,在檢查訪問說明符時,它會遵循One
。如果我們確實允許在Two
中標記foo
private,那麼編譯器會錯誤地允許我們通過obj
(它的類型爲One
)調用它,繞過保證只有對象本身可以調用private
方法。
真正的問題是在Java中不允許降低可見性。即使第一個方法被保護,第二個包爲私有,編譯器也可以編譯,但是不允許聲明。 – bestsss
@ bestsss-是的,這是真的,但這個決定背後的推理是對上述邏輯的擴展。 – templatetypedef
它會破壞多態性。
如果你有一個Two實例存儲在一個Two變量中,那麼foo不能被調用是有意義的。但是,如果您將One實例存儲在One變量中,那麼您只知道One。但是,一個人擁有公共福利,這可以被稱爲。這將是一個不一致,而且會很奇怪。
因爲繼承是是的關係。任何人都可以通過參考指的Two
一個實例One
:
One v = new Two();
什麼會的程序做,如果你呼籲V基準foo的方法是什麼?你打破了One的公共契約,保證One的每個實例都有一個(這裏是封裝保護的)foo方法。這就是編譯器禁止它的原因。
給出的答案給你技術上的解釋,爲什麼你不能一個接一個的擴展。我想給你一個理解,爲什麼這是不可能的,因爲面向對象的模式,而不是由於語言本身。
通常,第一類是帶有其訪問器的類的一般定義,即方法到外部世界。擴展這個類的子類必須爲外部世界提供相同的訪問者。兩個在你的例子中擴展一個,這意味着,Two提供了和One一樣的外部世界的訪問器。如果您要更改One的訪問器的可見性,則外部世界將無法再訪問您的類,因爲它們習慣使用類型爲One的對象進行訪問。
您無法降低Java中某個方法的可見性,您可以增加它,可見性順序(最低 - >最高):私有,私有包(即無修飾符),受保護,公共。 – bestsss