[英]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>
之間的區別
泛型是不變的:對於任何兩個不同的類型U
和V
, List<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 替換為第一個綁定類。
有關詳細信息泛型
對於下面的類:
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 Integer
、 Box
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
擦除了List
的E
所有外觀,對於List<Integer>
- E
將替換為Integer
。
對於您困惑的最后一部分,我建議您閱讀此內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.