[英]java generics type erasure
當聲明類型參數<T extends A & B & C>
的類<T extends A & B & C>
,類型擦除過程將用類型A
替換T
但是如果T
類型的變量調用接口B
或C
方法聲明,Java會用它做什么?
當我們創建一個泛型類型的實例,如ArrayList<String>
,類型參數String
也將被刪除,但是調用get
方法將返回類型String
,這些信息來自哪里,因為它已被刪除?
我知道使用java反射,但我需要一些具體的解釋。
不使用反射 - 鑄造是。 例如,請使用以下代碼:
interface A {
void a();
}
interface B {
void b();
}
interface C {
void c();
}
class Generic<T extends A & B & C> {
T t;
Generic(T t) {
this.t = t;
}
void callMethods() {
t.a();
t.b();
t.c();
}
}
現在看一下Generic
的字節碼(刪除了構造函數):
class Generic extends java.lang.Object{
A t;
void callMethods();
Code:
0: aload_0
1: getfield #2; //Field t:LA;
4: invokeinterface #3, 1; //InterfaceMethod A.a:()V
9: aload_0
10: getfield #2; //Field t:LA;
13: checkcast #4; //class B
16: invokeinterface #5, 1; //InterfaceMethod B.b:()V
21: aload_0
22: getfield #2; //Field t:LA;
25: checkcast #6; //class C
28: invokeinterface #7, 1; //InterfaceMethod C.c:()V
33: return
}
請注意每個invokeinterface
調用b()
和c()
之前的checkcast
指令。
結果就像Generic
實際上是這樣編寫的:
class Generic<T extends A> {
T t;
Generic(T t) {
this.t = t;
}
void callMethods() {
t.a();
((B) t).b();
((C) t).c();
}
}
至於你關於ArrayList
的問題 - 關於作為列表元素類型的get()
的返回類型的信息仍然存儲為ArrayList
類的一部分。 編譯器將再次在調用代碼中插入強制轉換,因此:
ArrayList<String> strings = new ArrayList<String>();
strings.add("foo");
String x = strings.get(0);
在執行時相當於:
ArrayList strings = new ArrayList();
strings.add("foo");
String x = (String) strings.get(0);
這個的一個重要方面是你不能在執行時詢問一個ArrayList
對象是什么T
- 該信息已被刪除。
在編譯器完成類型檢查后,類型擦除有效地用Object
替換所有泛型類型參數。 在你的<T extends A & B & C>
示例中, A
就像其他所有內容一樣被刪除。
當您在ArrayList<String>
上調用get
時,編譯器會生成字節碼,將返回的對象自動轉換為字符串。 列表本身並不“知道”它是一個字符串列表(由於類型擦除),但是調用get
的代碼知道它希望從列表中get
的東西是一個字符串。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.