簡體   English   中英

java泛型中類型擦除的邏輯是什么?

[英]what is the logic of type erasure in java generics?

據我所知,類型泛型發生在以下代碼中:

public class Test {

    public void a(List<Object> list) {
    }

    public void a(List<String> list){
    }

    public void a(List<Integer> list){
    }

}

當編譯器編譯代碼時,泛型類型將被擦除,因此所有簽名完全相同,如下所示:

public class Test {

    public void a(List list) {
    }

    public void a(List list){
    }

    public void a(List list){
    }

}

如果這是邏輯,那么:

List<Object> objList = new ArrayList<>();
List<String> strList = new ArrayList<>();
objList = strList;  

實際上是:

List objList = new ArrayList<>();
List strList = new ArrayList<>();
objList = strList; 

這是可以的,因為兩個列表都是相同的類型。 但是,在上面的代碼中, objList = strList會導致錯誤。

不太確定什么是真正的邏輯。 更重要的是, List<?> 、 List(不帶大括號)和List< Object>之間的區別

泛型是不變的:對於任何兩個不同的類型UVList<U>既不是List<V>的子類型也不是超類型。 (Joshua Bloch, Effective Java)

您不能將除null之外的任何值放入List<?>

List<?> 和 List 之間的區別在於前者可以采用 Object 類或任何其他對象的任何類型。 后者只能帶對象

List<Object> list = new ArrayList<String> // compile error

List<?> list = new ArrayList<String>  //no error

List<?extends Comparator> (boundedd) 將在編譯 List Unbounded 轉換為 Object 后轉換為 List,而對於 bounded,Java 編譯器將有界類型參數 T 替換為第一個綁定類。

有關詳細信息泛型

為了補充@Giorgi Tsiklauri 的回答

對於下面的類:

class Box<T> {
    T t;

    T getT() { return t; }

    void setT(T t) { this.t = t; }
}

由於類型擦除,編譯器將類編譯為:

class Box {
    Object t;

    Object getT() { return t; }

    void setT(Object t) { this.t = t; }
}

因此,當您使用類型參數Integer實例化Box<T>泛型類時,如下所示:

Box<Integer> box = new Box<Integer>();
box.setT(10);
Integer t = box.getT();

編譯器知道Box<T>是用Integer實例化的,因為在編譯時,它看到Box<Integer> 因此,類型轉換由編譯器插入。 所以上面的代碼被編譯成:

Box box = new Box();
box.setT(10);
Integer t = (Integer) box.getT(); // compiler inserts type casts in lieu of us!

無論您如何實例化泛型,編譯器都不會創建額外的類文件。 如果在類型擦除時實際發生的是替換(用Integer等類型參數替換T ),編譯器必須為Box for IntegerBox for Double等創建額外的類——但這不是在類型擦除時實際發生的情況:

如果類型參數是無界的,則將泛型類型中的所有類型參數替換為其邊界或Object Java™ 教程

必要時插入類型轉換以保持類型安全。 Java™ 教程

類型擦除確保不會為參數化類型創建新類; 因此,泛型不會產生運行時開銷。 Java™ 教程

如果這是這個邏輯,那么..

不,這不是發生的事情。

類型擦除是在編譯期間發生的一個過程,對於特定的對象分配(對象,使用new創建),編譯器擦除所有具有相應泛型類型參數(例如Box<Integer> )的泛型類型參數(例如Box<T> Box<Integer> ) .

這意味着,如果你已經定義了你的類:

class Box<T> {
}

然后調用該類型(實例化),如:

Box<Integer> intBox = new Box<>();

在編譯版本中, intBox實例化將在堆上分配對象,將T所有外觀與Integer交換。

因此,在您的示例中:

public class Test {

    public void a(List<Object> list) {
    }

    public void a(List<String> list){
    }

    public void a(List<Integer> list){
    }

}

您正在調用參數化類型(泛型)並使用泛型類型參數聲明方法的局部參數。

對於List<String>類型的變量所引用的對象,編譯器已經用String擦除了ListE所有外觀,對於List<Integer> - E將替換為Integer

對於您困惑的最后一部分,我建議您閱讀此內容

暫無
暫無

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

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