I never did that before but yesterday I actually wanted to see what happens with Type Erasure - a lot of Books give Examples like this (this one is form OCP 11)
public class Crate<T> {
private T contents;
public Crate() {
}
public T emptyCrate() {
return this.contents;
}
public void packCrate(T contents) {
this.contents = contents;
}
public static void main(String[] args) {
Crate<String> stringCrate = new Crate();
stringCrate.packCrate("content");
String content = (String)stringCrate.emptyCrate();
}
}
which supposedly compiles to that:
public class Crate {
private Object contents;
public Object emptyCrate() {
return contents;
}
public void packCrate(Object contents) {
this.contents = contents;
}
public static void main(String[] args) {
Crate stringCrate = new Crate();
stringCrate.packCrate("content");
String content = (String)stringCrate.emptyCrate();
}
}
but it actually compiles to this:
public class Crate<T> {
private T contents;
public Crate() {
}
public T emptyCrate() {
return this.contents;
}
public void packCrate(T contents) {
this.contents = contents;
}
public static void main(String[] args) {
Crate<String> stringCrate = new Crate();
stringCrate.packCrate("content");
String content = (String)stringCrate.emptyCrate();
}
}
I use FernFlower in IntelliJ to decompile. Basically rthe only thing changes is the
String content = (String)stringCrate.emptyCrate();
so my Question now: are the books wrong, are there any flags on the compiler to remove information, is the Decompiler too smart and how can I actually see the Code created by the Compiler?
CodePudding user response:
The point that the book is trying to make, is that the runtime doesn't care about generic type parameters. It shows that this is the case by pedagogically "lying" to you that the class file does not contain any generic type variables or arguments, which is understandable, but also not true.
The class file does contain type variables and generic arguments used in field, method, and class declarations. You can even get them with reflection!
// Both of these will print T
System.out.println(Crate.class.getTypeParameters()[0]);
System.out.println(Crate.class.getDeclaredField("contents").getGenericType());
It's just that the runtime doesn't care if e.g. you have assigned something that is not T
into a field that is supposedly of type T
.
On the other hand, local variable's generic types are kept in the class file if you include debug information when compiling your code (-g:vars
). This is why you can see Crate<String>
in your class file. If you did -g:none
, it will be shown as:
Crate var1 = new Crate();
in IntelliJ. Note that the variable's name is gone too :)