Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Java Generics Type Erasure, compiler output different to what OCP book says

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

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 🙂

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading