As per the java documentation on Erasure of Generic Types,
Consider the following generic class that represents a node in a singly linked list:
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; }
// ...
}
Because the type parameter T is unbounded, the Java compiler replaces it with 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; }
// ...
}
But after compilation with Java 1.7.0_11, when I opened it with any decompiler I can see the same code as like source code.
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;
}
}
If Type-Erasure applied at compile then the byte code must not contain Generic information as shown above. Kindly clarify me.
NOTE: I am using JD-GUI as a decompiler to analyze the byte code
Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to: Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded.
- Erasure is a type of alteration in document. It can be classified as chemical erasure and physical erasure.
The whole point is that reified generics have support in the compiler for preserving type information, whereas type erased generics don't. AFAIK, the whole point of having type erasure in the first place was to enable backwards compatibility (e.g. lower versioned JVMs could still understand generic classes).
Reified Generics is a generics system that makes generics type information available at runtime. C# is one language that supports Reified Generics natively, as opposed to Java's Type-Erased Generics.
The bytecode contains meta information about the code itself, such as generic types (or variable names) - it does not mean it's useable by the JVM.
The disassembled bytecode of your class looks like below (you can see it with 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
}
You can see that the methods and arguments generic types are there but the code itself refers to Object as expected due to the erasure process.
The fact that the class is generic is retained. For instance, at runtime you can call
Node.class.getTypeParameters()
The next bit of code will return "T".
(new Node<Integer>()).getClass().getTypeParameters()[0].getName()
You can't get the value of type parameters at runtime, but the JVM knows they're there.
Erasure comes into play when you construct a instance.
Node<Integer> node = new Node<Integer>(1, null);
Integer i = node.getData();
Becomes
Node node = new Node(1, null);
Integer i = (Integer)node.getData();
Generic classes are always generic. But instances do not carry generic type information inside them. The compiler verifies that everything you've done agrees with the generic type and then inserts casts.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With