Uma característica importante dos tipos paramétricos é a capacidade de escrever algoritmos polimórficos, ou seja, algoritmos que operam em uma estrutura de dados independentemente do seu valor de parâmetro, como Arrays.sort()
.
Com genéricos, isso é feito com tipos curinga:
<E extends Comparable<E>> void sort(E[]);
Para ser realmente útil, os tipos de caracteres curinga requerem captura de caracteres curinga, e isso requer a noção de um parâmetro de tipo. Nada disso estava disponível no momento em que as matrizes foram adicionadas ao Java, e as matrizes de makes do tipo covariante de referência permitiram uma maneira muito mais simples de permitir algoritmos polimórficos:
void sort(Comparable[]);
No entanto, essa simplicidade abriu uma brecha no sistema de tipo estático:
String[] strings = {"hello"};
Object[] objects = strings;
objects[0] = 1; // throws ArrayStoreException
exigindo uma verificação de tempo de execução de todo acesso de gravação a uma matriz do tipo de referência.
Em poucas palavras, a abordagem mais recente incorporada pelos genéricos torna o sistema de tipos mais complexo, mas também mais estaticamente seguro, enquanto a abordagem mais antiga era mais simples e menos segura do tipo estaticamente. Os projetistas da linguagem optaram pela abordagem mais simples, tendo coisas mais importantes a fazer do que fechar uma pequena brecha no sistema de tipos que raramente causa problemas. Mais tarde, quando o Java foi estabelecido e as necessidades prementes foram atendidas, eles tinham os recursos necessários para fazer o correto para genéricos (mas alterá-lo para matrizes teria quebrado os programas Java existentes).