Middle
Como o Java lida com generics?
sobes.tech IA
Resposta da IA
O Java lida com genéricos através da eliminação de tipos (type erasure).
Durante a compilação, a informação sobre os tipos genéricos é removida. Isso significa que na bytecode, a classe ArrayList<String> e ArrayList<Integer> parecerão iguais, ambas como ArrayList. Em vez dos parâmetros genéricos, o compilador insere Object ou a fronteira superior do tipo restrito. Nos locais onde os tipos são usados, o compilador insere casts implícitos.
Vantagens da eliminação de tipos:
- Compatibilidade com versões anteriores do Java: Código com genéricos pode interagir com código escrito antes de sua introdução, pois o bytecode não contém informações de tipos.
- Ausência de custos adicionais em tempo de execução: Como a informação sobre os tipos genéricos é removida, não há necessidade de verificações de tipos em tempo de execução, o que pode melhorar o desempenho.
Desvantagens da eliminação de tipos:
- Impossibilidade de usar tipos primitivos como parâmetros genéricos: Por exemplo,
ArrayList<int>não é válido. É necessário usar seus wrappers (ArrayList<Integer>). - Perda de informação de tipo em tempo de execução: Isso pode dificultar algumas operações, como criar um array de um tipo genérico (
new T[size]) ou verificar a compatibilidade de tipos (instanceof).
Exemplo de conversão de tipo implícita após a eliminação:
// Criação de uma lista genérica
List<String> stringList = new ArrayList<>();
stringList.add("Hello");
// Em bytecode, isso parece aproximadamente assim (após a eliminação):
// List stringList = new ArrayList();
// stringList.add("Hello"); // obj.add(java.lang.Object)
// Obter um elemento da lista
String greeting = stringList.get(0);
// Em bytecode, o compilador adiciona cast:
// String greeting = (String)stringList.get(0);
Os genéricos limitados (bounded wildcards) são usados para gerenciar de forma mais flexível os tipos de parâmetros.
<? extends T>: Indica qualquer tipo que estenda ou seja T. Permite ler elementos como T ou seus subtipos.<? super T>: Indica qualquer tipo restrito a T ou seu supertipo. Permite adicionar elementos de tipo T ou seus subtipos.
// Exemplo com <? extends>
List<? extends Number> numbers = new ArrayList<Integer>();
Number num = numbers.get(0); // OK
// numbers.add(new Double(1.0)); // Erro de compilação
// Exemplo com <? super>
List<? super Integer> integers = new ArrayList<Number>();
integers.add(10); // OK
// Integer i = integers.get(0); // Erro de compilação, retorna Object