Los genéricos permiten definir clases, métodos e interfaces parametrizados por tipo. En lugar de trabajar con Object y hacer casting manual, el compilador garantiza type safety en tiempo de compilación.
// Sin genéricos — ClassCastException en runtime
List lista = new ArrayList();
lista.add("texto");
String s = (String) lista.get(0);
// Con genéricos — error en compilación
List<String> lista = new ArrayList<>();
lista.add("texto");
String s = lista.get(0); // sin castingType erasure: en tiempo de ejecución, los tipos genéricos se borran y se reemplazan por Object (o el bound superior). Esto significa que List<String> y List<Integer> son el mismo tipo en runtime.
Wildcards y la regla PECS:
| Wildcard | Uso | Regla |
|---|---|---|
<? extends T> |
Leer (Producer) | Solo lectura del tipo T |
<? super T> |
Escribir (Consumer) | Solo escritura del tipo T |
<?> |
Sin restricción | Solo lectura de Object |
PECS = Producer Extends, Consumer Super:
// Producer: lees elementos de la lista → extends
void imprimir(List<? extends Number> numeros) { ... }
// Consumer: añades elementos a la lista → super
void añadir(List<? super Integer> lista) { lista.add(42); }Tipos genéricos acotados:
<T extends Comparable<T>> // T debe implementar Comparable
<T extends Number & Cloneable> // múltiples boundsMétodos genéricos:
public <T> List<T> repetir(T elemento, int n) { ... }- Type safety en compilación: elimina
ClassCastExceptionen runtime. - Código reutilizable sin duplicación para distintos tipos.
- APIs más expresivas y auto-documentadas.
- Elimina el casting manual.
Ver ExpGenericsBasics.java, Comodines.java y GenericsCheatSheet.java para ejemplos de wildcards, PECS y métodos genéricos.