Now for the answer. Using the insert
method to add an Integer
to our list is quite safe and permissible, as it matches the type we have specified for our myList
variable. But when we try to insert a String
into an ArrayList
that was meant to hold only Integer
values, then there is a problem, not at compile time but at runtime, when you try to invoke an Integer
-specific method on your wrongly added String
instance.
There is one thing you ought to understand in order to understand this entire question and its purpose - The JVM has no idea that you were trying to insert a String
into an ArrayList
meant to hold only Integer
s. All your generics and their type-safety are restricted to compile time only. Through a process called "type erasure", the compiler removes all of the type parameters from the generic code. In other words, even though you wrote something like this:
List<Integer> myList = new ArrayList<>();
Becomes the following after the compiler is done with it:
List myList = new ArrayList();
However, why did they keep Generics like this?
The answer is simple! If it wouldn't have been for this weird behavior then the legacy code from earlier versions of Java would have been broken and Million Java developers would have to edit Trillions of their old Java code to make it work again!!
But don't blame the compiler; when you try to run the code, the compiler tries to warn you with the following warning:
$> javac TestInserter.java
Note: TestInserter.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
And when you do as the compiler asks you to do as follows:
$> javac -Xlint:unchecked TestInserter.java
TestInserter.java:15: warning: [unchecked] unchecked call to add(E) as a member of the raw type List
list.add(new String("55"));
^
where E is a type-variable:
E extends Object declared in interface List
1 warning
As far as the compiler is concerned, it tries to tell you that it suspects that some code in your program might end up in trouble.
To wrap it up, Think of generics as just compile time protection. The compiler uses the type information (Type specified in parameter) to make sure that you don't insert the wrong things into a collection (or a user defined generic type) and that you don't fetch values from the wrong reference type. All of the generic protection is compile time! That's it for this.