Key objective of generics in java is to achieve compile time type safety.
: Why above two cases compiled successfully with unsafe warnings?
In case I you try to tell the compiler that you are creating a type safe reference to an unsafe ArrayList object.
In case II you try to tell the compiler that you are creating an unsafe reference to a type safe ArrayList object.
Because of the type un-safety, both cases does not cause the compilation to be failed and you will see the successful compilation, but with warnings.
: What is the difference in Case I and Case II?
Since we are talking about compile time only as I mentioned initially , compiler is unable to see the actual objects. So the compiler make decisions using the object references not using the actual objects in the heap.
So you cannot do the following invocation without compile error in Case I
But you can do the same invocation in Case II.
Also note that after everything type-erasure erases all generic declarations at runtime