Sobes.tech
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