Um tipo genérico é uma classe ou interface genérica parametrizada sobre tipos. Isto permite que o compilador imponha segurança de tipos à classe ou à interface.
Considera esta interface Container não genérica:
class Container {
private Object object;
public void set(Object object) { this.object = object; }
public Object get() { return object; }
}
Como aceita e devolve tipos Object, funciona com qualquer tipo não primitivo.
No entanto, isto tem um custo, porque algum código pode chamar get à espera de Integers, enquanto outro código chama set e acrescenta Strings, o que resulta numa exceção em tempo de execução.
Uma classe genérica e uma interface genérica têm os seguintes formatos:
class ClassName<T1, T2, ..., Tn> { ... }
interface InterfaceName<T1, T2, ..., Tn> { ... }
A secção de parâmetros de tipo, delimitada por sinais de menor e maior (<>), a seguir ao nome da classe ou da interface, especifica os parâmetros de tipo (também chamados de variáveis de tipo) T1, T2, ..., e Tn.
Estes podem ser usados dentro do corpo da classe ou da interface para obter segurança de tipos genérica.
Aqui está a versão genérica de Container:
class Container<E> {
private E object;
public void set(E object) { this.object = object; }
public E get() { return object; }
}
Ao criá-la, temos agora de declarar que tipo contém, e o compilador vai impor essa restrição:
// empty <> can infer from context
Container<String> stringContainer = new Container<>();
// compiler knows this is a String, so it is allowed
stringContainer.set("Some string");
// no cast needed, compiler knows it is a String
String result = stringContainer.get();
// this causes a compiler error:
stringContainer.set(42);