當默認方法被子類的靜態方法覆蓋時,為什么 Java 8 編譯失?。?/h1>
3 回答

TA貢獻1797條經驗 獲得超4個贊
Father這里不是問題,因為來自接口的靜態方法不是繼承的(例如List.of(..)不能通過調用ArrayList.of(..))所以沒有覆蓋/隱藏,這也意味著沒有沖突。
因此我們可以安全地寫
interface Father {
static void method() { }
}
interface Child extends Father {
static void method() { }
}
問題是繼承default void method() { }自接口的方法,這意味著之后MotherChild
interface Child extends Father, Mother {
static void method() { }
}
你最終會得到有兩個method()版本的接口:靜態和非靜態(默認)
interface Child extends Father, Mother {
static void method() { }
default void method() { } //inherited from Mother
}
但為什么這是個問題?
假設您想向Child接口添加另一個方法,該方法將調用method()
interface Child extends Father, Mother {
static void method() { }
default void method() { } //inherited from Mother
default void demo(){
method(); //which code block should be executed?
}
}
它應該從靜態方法() 還是從默認方法() 執行代碼?編譯器將無法決定。
雖然這種情況可以通過使用來解決
Child.method()對于靜態方法,
this.method()對于默認方法(是的,它不會有歧義,因為靜態方法不會this被實例化的類繼承),
重點是首先要防止此類問題。這就是為什么我們被要求不能在一個地方(定義或繼承)具有相同簽名(名稱+參數類型)的靜態和非靜態方法。

TA貢獻2019條經驗 獲得超9個贊
這是一個有趣的情況。我認為簡單的答案是靜態方法從未被允許隱藏(它們不能覆蓋)基類中的非靜態方法。如果您static
從 中刪除修飾符Father
,那也會導致 Child 無法編譯。這可能是為了避免混淆。
所以默認方法只是遵循現有規則。
“但是等一下”,您可能會想,“添加默認方法的目的是明確允許庫開發人員在不破壞現有代碼的情況下將新功能引入舊接口。如果任何現有代碼具有名稱沖突的靜態方法 - 不會它壞了?”
其實我覺得不一定。IIRC,這是一個有意允許二進制兼容性和源兼容性不同的地方。我想你會發現如果:
interface Child
(和使用它的東西)已經被編譯,而默認方法不存在于interface Mother
, 和您稍后將默認方法添加到該源文件并僅
interface Mother
編譯該源文件。
然后我認為你最終會得到工作正常的代碼(在字節碼/JVM 級別)。但是,它會在您嘗試針對 interface Child
更新的interface Mother
.
添加回答
舉報