Una característica importante de los tipos paramétricos es la capacidad de escribir algoritmos polimórficos, es decir, algoritmos que operan en una estructura de datos independientemente de su valor de parámetro, como Arrays.sort()
.
Con los genéricos, eso se hace con los tipos comodín:
<E extends Comparable<E>> void sort(E[]);
Para ser realmente útiles, los tipos de comodines requieren captura de comodines, y eso requiere la noción de un parámetro de tipo. Nada de eso estaba disponible en el momento en que se agregaron matrices a Java, y hacer matrices de tipo covariante de referencia permitió una forma mucho más simple de permitir algoritmos polimórficos:
void sort(Comparable[]);
Sin embargo, esa simplicidad abrió un vacío en el sistema de tipo estático:
String[] strings = {"hello"};
Object[] objects = strings;
objects[0] = 1; // throws ArrayStoreException
requiere una verificación de tiempo de ejecución de cada acceso de escritura a una matriz de tipo de referencia.
En pocas palabras, el enfoque más nuevo incorporado por los genéricos hace que el sistema de tipos sea más complejo, pero también más seguro de tipo estático, mientras que el enfoque más antiguo era más simple y menos seguro de tipo estático. Los diseñadores del lenguaje optaron por un enfoque más simple, que tenían cosas más importantes que hacer que cerrar un pequeño vacío en el sistema de tipos que rara vez causa problemas. Más tarde, cuando se estableció Java, y se atendieron las necesidades apremiantes, tenían los recursos para hacerlo bien en genéricos (pero cambiarlo por matrices habría roto los programas Java existentes).