Matteo Caprari home

Where are generics stored in java compiled classes?

posted on 24 Feb 2011

I was having a go at learning some Java bytecode and started looking at how generics were handled. As expected, the compiler was emitting cast instructions when generic types where used, but nothing where the types where declared: generics in Java are implemented using a technique called "erasure".

Straight from the docs:

When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics. from java docs

But sure not ALL information about the type parameters is lost. That would mean that once I compile my code, all other developer would use it "the old way", with casts and all, but clearly this is not the case. Let's write two simple classes:

public class GenericClass<T> {}

public class StandardClass {}

And decompile them:

$ javap -c GenericClass
public class learn.GenericClass extends java.lang.Object{
public learn.GenericClass();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return
}

$ javap  -c StandardClass
Compiled from "StandardClass.java"
public class learn.StandardClass extends java.lang.Object{
public learn.StandardClass();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return
}

As it should, the bytecode looks exactly the same. No type parameters.

Let's invoke the same command again with -verbose to see some more detail:

$ javap -verbose StandardClass
Compiled from "StandardClass.java"
public class learn.StandardClass extends java.lang.Object
  SourceFile: "StandardClass.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = class        #2;     //  learn/StandardClass
// ... snip
const #15 = Asciz       StandardClass.java;
// ... snip

$ javap -verbose GenericClass
Compiled from "GenericClass.java"
public class learn.GenericClass extends java.lang.Object
  SourceFile: "GenericClass.java"
  Signature: length = 0x2
   00 13
  minor version: 0
  major version: 50
  Constant pool:
const #1 = class        #2;     //  learn/GenericClass
// ... snip
const #19 = Asciz       Ljava/lang/Object;;

The two outputs are different at last: the constant_pool section of a class file has an optional "signature" field. This optional can specify the full signature of the class, including type parameters. The compiler can then use this information to do the right thing when turns sources into binaries.This stuff is specified in the section "4.8.8 The Signature Attribute" of the updated JVM Specification.

blog comments powered by Disqus