[英]Why can’t we override a base class method with private extended class method?
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 語言不允許子類降低子類中方法、字段或類的可見性,因此,降低foo
方法可見性的Two
類是不合法的。
為什么降低能見度是一個問題?
考慮我們要使用One
類的情況:
class AnotherClass {
public void someMethod() {
One obj = new One();
obj.foo(); // This is perfectly valid.
}
}
在這里,在One
實例上調用foo
方法是有效的。 (假設AnotherClass
類與One
類在同一個包中。)
現在,如果我們要實例化Two
對象並將其放在One
類型的obj
變量中呢?
class AnotherClass {
public void someMethod() {
One obj = new Two();
obj.foo(); // Wait a second, here...
}
}
Two.foo
方法是私有的,但是One.foo
方法允許訪問該方法。 我們這里有問題。
因此,在考慮繼承時允許降低可見性沒有多大意義。
鏈接
這段代碼的問題在於,如果它是合法的,那么如果您通過One
基類間接訪問它,Java 將無法尊重foo
的private
修飾符。 例如,如果我要寫
One obj = new Two();
obj.foo();
然后我們會遇到麻煩,因為我們將間接調用Two
的private
方法foo
,因為當編譯器檢查obj.foo()
它會查看One
以確定foo
是否可訪問,而不是在Two
。 這樣做的原因是編譯器不能總是告訴obj
可能指向什么 - 例如,如果我寫了類似的東西
One obj = Math.random() < 0.5? new One() : new Two();
obj.foo();
那么編譯器就無法知道obj
指向One
還是指向Two
。 因此,它在檢查訪問說明符時遵循One
。 如果我們確實被允許在Two
標記foo
private ,那么編譯器會錯誤地允許我們通過obj
調用它,它的類型為One
,繞過只有對象本身可以調用private
方法的保證。
給出的答案為您提供了為什么不能一一擴展的技術解釋。 我想讓你理解為什么這是不可能的,因為面向對象模式而不是因為語言本身。
通常,類 One 是一個類的一般定義,它帶有外部世界的訪問器、方法。 擴展此類的子類必須為外部世界提供相同的訪問器。 在您的示例中,兩個擴展了一個,這意味着兩個為外部世界提供了與 One 相同的訪問器。 如果您要更改 One 訪問器的可見性,外部世界將無法再訪問您的類,因為它們習慣於對類型為 One 的對象進行訪問。
它會破壞多態性。
如果你有一個 Two 實例存儲在 Two 變量中,那么不能調用 foo 是有道理的。 但是,如果將 Two 實例存儲在 One 變量中,則您只知道 One。 但是 One 有一個公共 foo,可以調用它。 這將是不一致的,並且真的很奇怪。
因為繼承是一種關系。 任何人都可以通過引用One
來引用Two
的實例:
One v = new Two();
如果你在 v 引用上調用 foo 方法,程序會做什么? 你破壞了 One 的公共契約,它保證 One 的每個實例都有一個(這里是包保護的)foo 方法。 這就是編譯器禁止它的原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.