簡體   English   中英

擦除如何處理Java中的覆蓋場景?

[英]how does erasure handles overriding scenarios in Java?

這個問題來自我之前的帖子 在發布我的問題之前,我正在粘貼oracle docs中的內容;

8.4.8.1. Overriding (by Instance Methods)

An instance method m1, declared in class C, overrides another instance method m2, declared in class A iff all of the following are true:

    C is a subclass of A.

    The signature of m1 is a subsignature (§8.4.2) of the signature of m2.

8.4.2. Method Signature 
The signature of a method m1 is a subsignature of the signature of a method m2 if either:

    m2 has the same signature as m1, or

    the signature of m1 is the same as the erasure (§4.6) of the signature of m2.

當涉及overriding時我對type erasure理解如下:如果在erasure之后, signature of m1 and m2signature of m1 and m2是相同的,那么它們被認為是被overridden 所以在上面的上一篇文章中,我嘗試override一個parent class method ,該parent class method通過subclass method parent class method獲取List<String> ,該subclass method采用List<Integer>假設在type erasure之后剩下的只是List<Object> 但那是錯的。 因此,在涉及erasure時,我對上述方法overriding定義的理解是完全錯誤的。 可以舉出一些簡單的例子來解釋上述觀點。

謝謝。 順便說一句,以上幾點來自這里。

方法是否覆蓋另一方法不僅僅處理方法的擦除。 編譯器確定方法是否覆蓋另一個方法,並且它可以在類型擦除發生之前訪問所涉及的泛型類型參數。

您對使用擦除來確定覆蓋的想法並不完全正確。 讓我們在討論中添加以下JLS Section 8.4.8.1

在類C中聲明的實例方法m1將覆蓋在類A中聲明的另一個實例方法m2,如果以下所有條件都為真:

  • C是A的子類。

  • m1的簽名是m2簽名的子簽名(§8.4.2)。

  • 或者:

    • m2在與C相同的包中是公共的,受保護的或聲明的,具有默認訪問權限

    • m1覆蓋方法m3(m3與m1不同,m3與m2不同),使得m3覆蓋m2。

要求m1m2的子簽名,但不是相反。

例1:

class A {
   public void foo(List<String> list) { }
}

class B extends A {
   @Override
   public void foo(List list) {}
}

這是合法的,因為簽名Bfoo的方法是相同的擦除Afoo方法。

例2:

class A {
   public void foo(List list) { }
}

class B extends A {
   @Override
   public void foo(List list) {}
}

這是合法的,因為簽名是相同的(即使它們是原始的)。

例3:

class A {
   public void foo(List list) { }
}

class B extends A {
   @Override
   public void foo(List<Integer> list) {}
}

這是不合法的,因為不考慮最重要方法的擦除。 也就是說,將List<Integer>List的擦除進行比較, List仍然只是List ,它們不一樣。

例4:

class A {
   public void foo(List<String> list) { }
}

class B extends A {
   @Override
   public void foo(List<Integer> list) {}
}

這也是不合法的,因為不考慮重寫方法的擦除。 也就是說,將List<Integer>List<String>List )的擦除進行比較,它們不相同。

您無法在重寫方法中更改參數的泛型類型參數(例如, List<String>List<Integer> 。在覆蓋不使用泛型的方法時,不能引入泛型(例如( List to List<Integer> )但是,您可以在覆蓋時刪除泛型(例如List<String> to List )。

因為Java是一種嚴格類型的語言,所以必須注意協方差以及類型如何協同工作。 擦除不是打破類型規則的借口。

例如:

class BaseGood<T> {
    public void doStuff(T elem) {
                // ...
    }
}
class DerivedGood<T> extends BaseGood {
    public void doStuff(Object elem) {
        super.doStuff(elem);
    }
}
class BaseBad {
    public void doStuff(List<Double> list) {
        // ...
    }
}
class DerivedBad extends BaseBad {
    public void doStuff(List<Integer> list) {
        super.doStuff(list);
        // ...
    }
}

在這里,我們有兩種不同的擦除案例。

使用BaseGoodDerivedGood類,這兩個方法具有相同的擦除: void doStuff(Object elem) ,並且可以知道T將始終是Object類型,因此該函數是類型安全的。

使用BaseBadDerivedBad類,這兩個方法具有相同的擦除: void doStuff(List list) ; 但是,類型系統無法安全地從List<Integer>轉換為List<Double> (或者與任何List的轉換)。 允許這種轉換可能會允許嘗試將Double s放入Integer列表中(或者泛型將檢測到的時間轉移到編譯時)。

擦除后方法覆蓋友好並不意味着類型系統不能檢查不兼容性預擦除。

編輯

此外,應用於類/方法定義的實際擦除不會在編譯時發生,而是在運行時發生。 引用泛型方法的代碼只是編譯,好像函數是在沒有泛型的情況下調用的,由編譯器和運行時檢查強制執行類型安全。

請參閱: Java泛型 - 類型擦除 - 何時以及發生了什么

還有另一種情況,您將類型擦除的泛型類傳遞給覆蓋,並且因為類型系統無法檢查您是否根據方法的類型傳遞了正確的列表,它必須允許它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM