Creo que otras respuestas han dicho esto hasta cierto punto, pero no muy claramente. Uno de los problemas con los genéricos es perder los tipos genéricos durante el proceso de reflexión. Así por ejemplo:
List<String> arr = new ArrayList<String>();
assertTrue( ArrayList.class, arr.getClass() );
TypeVarible[] types = arr.getClass().getTypedVariables();
Desafortunadamente, los tipos devueltos no pueden decirle que los tipos genéricos de arr son String. Es una diferencia sutil, pero es importante. Debido a que arr se crea en tiempo de ejecución, los tipos genéricos se borran en tiempo de ejecución, por lo que no puede resolverlo. Como algunos dijeron, se ArrayList<Integer>
ve igual que ArrayList<String>
desde el punto de vista de la reflexión.
Es posible que esto no le importe al usuario de Generics, pero supongamos que queríamos crear un marco sofisticado que utilizara la reflexión para descubrir cosas elegantes sobre cómo el usuario declaró los tipos genéricos concretos de una instancia.
Factory<MySpecialObject> factory = new Factory<MySpecialObject>();
MySpecialObject obj = factory.create();
Digamos que queríamos una fábrica genérica para crear una instancia MySpecialObject
porque ese es el tipo genérico concreto que declaramos para esta instancia. Bueno, la clase Factory no puede interrogarse para averiguar el tipo concreto declarado para esta instancia porque Java los borró.
En los genéricos de .Net puede hacer esto porque en tiempo de ejecución el objeto sabe que son tipos genéricos porque el compilador lo cumplió en el binario. Con borrados, Java no puede hacer esto.