Java generics use type erasure, meaning those parameterized types aren’t retained at runtime so this is perfectly legal:
List<String> list = new ArrayList<String>();
list.put("abcd");
List<Integer> list2 = (List<Integer>)list;
list2.add(3);
because the compiled bytecode looks more like this:
List list = new ArrayList();
list.put("abcd");
List list2 = list;
list2.add(3); // auto-boxed to new Integer(3)
Java generics are simply syntactic sugar on casting Object
s.