When do Java generics use casting at runtime?

generics, java

Solution

Here is a short program I wrote:

public class Test<T> {

  public T contents;

  public Test(T item) {
    contents = item;
  }

  public static void main(String[] args) {

    Test<String> t = new Test<String>("hello");
    System.out.println(t.contents);

  }

}

Try compiling it with `javac`, and then look at the bytecode with `javap -verbose`. I've selected a few interesting lines:

public java.lang.Object contents;

This should turn up just before the definition of the Test constructor. In the example code it was of type T, now it is an Object. That's erasure.

Now, looking at the main method:

public static void main(java.lang.String[]);
Code:
   Stack=3, Locals=2, Args_size=1
   0:   new #3; //class Test
   3:   dup
   4:   ldc #4; //String hello
   6:   invokespecial   #5; //Method "<init>":(Ljava/lang/Object;)V
   9:   astore_1
   10:  getstatic   #6; //Field java/lang/System.out:Ljava/io/PrintStream;
   13:  aload_1
   14:  getfield    #2; //Field contents:Ljava/lang/Object;
   17:  checkcast   #7; //class java/lang/String
   20:  invokevirtual   #8; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   23:  return

Then we can see the `checkcast` command at line 17, just before the println - this is where Java casts from `Object` to the erased generic type - `String`

Problem

I was reading a discussion about C++ templates and C# generics, and how they are different from Java's type-erased generics. I read a statement that said that Java still uses casting at runtime, for instance when dealing with collections. If this is true, I wasn't aware of it! Let's say that I have code such as: ``` ArrayList<SomeClass> list = new ArrayList<SomeClass>(); ... SomeClass object = list.get(0); ``` My question is. Is this effectively compiled to ``` ArrayList list = new ArrayList(); ... SomeClass object = (SomeClass) list.get(0); ``` If so, why? I thought that the fact that list is of type `ArrayList<SomeClass>` guarantees, at compile time and run time, that only SomeClass will be stored inside the ArrayList? Or can you ever do unsafe type-casting to transform an `ArrayList<OtherClass>` into an `ArrayList<SomeClass>`? Are there other occasions where at-runtime type casting is done in Java generics? Finally, if casting at run time is indeed used, are there occasions when the JIT can elide the run time cast check? (Please refrain from answering/commenting that micro-optimisations are not worth it, preemptive optimisation is root of all evil, etc. I see these on other similar questions. These points are well understood, but they do not take away the point of trying to understand how type-erased generics are implemented under the hood.)

Original source