[英]Java Generics Type Erasure byte code
根據關於Erasure of Generic Types的java文檔,
考慮以下表示單鏈表中節點的泛型類:
public class Node<T> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) }
this.data = data;
this.next = next;
}
public T getData() { return data; }
// ...
}
因為類型參數T是無界的,所以Java編譯器將其替換為Object :
public class Node {
private Object data;
private Node next;
public Node(Object data, Node next) {
this.data = data;
this.next = next;
}
public Object getData() { return data; }
// ...
}
但是在使用Java 1.7.0_11編譯之后,當我用任何反編譯器打開它時,我可以看到與源代碼相同的代碼。
public class Node<T>
{
private T data;
private Node<T> next;
public Node(T paramT, Node<T> paramNode)
{
this.data = paramT;
this.next = paramNode;
}
public T getData()
{
return this.data;
}
}
如果在編譯時應用Type-Erasure,則字節代碼不得包含如上所示的通用信息。 請澄清我。
注意:我使用JD-GUI作為反編譯器來分析字節碼
字節碼包含有關代碼本身的元信息,例如泛型類型(或變量名稱) - 它並不意味着JVM可以使用它。
你的類的反匯編字節碼如下所示(你可以用javap -c Node.class
看到它):
public class Node<T> {
public Node(T, Node<T>);
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #2 // Field data:Ljava/lang/Object;
9: aload_0
10: aload_2
11: putfield #3 // Field next:LNode;
14: return
public T getData();
Code:
0: aload_0
1: getfield #2 // Field data:Ljava/lang/Object;
4: areturn
}
您可以看到方法和參數泛型類型存在,但由於擦除過程,代碼本身會按預期引用Object。
保留了類是通用的這一事實。 例如,在運行時您可以調用
Node.class.getTypeParameters()
下一位代碼將返回“T”。
(new Node<Integer>()).getClass().getTypeParameters()[0].getName()
您無法在運行時獲取類型參數的值,但JVM知道它們在那里。
構造實例時,擦除會發揮作用。
Node<Integer> node = new Node<Integer>(1, null);
Integer i = node.getData();
變
Node node = new Node(1, null);
Integer i = (Integer)node.getData();
通用類總是通用的。 但是實例不會在其中包含泛型類型信息。 編譯器會驗證您所做的所有事情是否與泛型類型一致,然后插入強制轉換。
通用類型信息仍保存在字節碼中,特別是在類成員的簽名信息中。
例如,執行javap -verbose Node.class
產生:
...
LocalVariableTypeTable:
Start Length Slot Name Signature
0 5 0 this Ltest/Node<TT;>;
請參閱JVM規范中的此部分 :
簽名編碼以Java編程語言編寫的聲明,這些聲明使用Java虛擬機類型系統之外的類型。 它們支持反射和調試,以及只有類文件可用時的編譯。
Java編譯器必須為其聲明使用類型變量或參數化類型的任何類,接口,構造函數,方法或字段發出簽名。 具體來說,Java編譯器必須發出:
任何類或接口聲明的類簽名,它是通用的,或者具有參數化類型作為超類或超接口 ,或兩者。
任何方法或構造函數聲明的方法簽名,它是通用的,或者具有類型變量或參數化類型作為返回類型或形式參數類型 ,或者在throws子句中具有類型變量,或者它們的任何組合。
大家,
我希望它只是反編譯器問題,即JD-GUI 。
當我用不同的反編譯器即JDecompiler打開時,我能夠看到預期的字節碼如下:
public class Node {
private Object data;
private Node next;
public Node(Object obj, Node node) {
/* 7*/ data = obj;
/* 8*/ next = node;
}
public Object getData() {
/* 12*/ return data;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.