When do java generics use transformations at run time?
I'm reading a discussion about C templates and c# generics and how they differ from Java type erasure generics I read a statement that Java still uses transformations at runtime, such as when dealing with collections If this is true, I don't know it!
Suppose I have the following code:
ArrayList<SomeClass> list = new ArrayList<SomeClass>(); ... SomeClass object = list.get(0);
My problem is Is this a valid compilation
ArrayList list = new ArrayList(); ... SomeClass object = (SomeClass) list.get(0);
If so, why? I think the type of list is ArrayList < < someclass >, which ensures that only someclass is stored in ArrayList at compile time and runtime? Or can you do unsafe type conversion to convert ArrayList < otherclass > to ArrayList < someclass >?
Are there other occasions for runtime type conversion in Java generics?
Finally, if you do use a run-time transformation, can the JIT ignore the run-time transformation check?
(please don't answer / comment that micro optimization is not worth it. Preemptive optimization is the source of all evil, etc. I have seen these on other similar questions. These points are well understood, but they don't take away trying points to understand how to implement type erasure generics under the hood.)
Solution
This 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 to compile it in javac, and then use javap - verbose to view the bytecode I chose several interesting lines:
public java.lang.Object contents;
This should occur before the definition of the test constructor In the sample code, it is type T, and now it is an object This is erasure
Now let's look at the main methods:
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 on line 17, just before println - this is the string that Java converts from object to erased generic type - string