Nivel 2 · 20 min
Generics
Los generics de Java habilitan colecciones y algoritmos type-safe en tiempo de compilación. Entender el borrado de tipos, los wildcards acotados y el principio PECS es esencial para escribir código de librería reutilizable y evitar sorpresas de ClassCastException en runtime.
Borrado de tipos y tipos reificables
Los generics de Java usan borrado de tipos: los parámetros de tipo genérico se eliminan en tiempo de compilación y se reemplazan con Object (o el límite superior para tipos acotados). Esto es para compatibilidad con bytecode pre-generics. Consecuencia: List'<'String'>' y List'<'Integer'>' son el mismo tipo en runtime — no podés hacer instanceof List'<'String'>' ni crear new T[]. Los tipos reificables son tipos cuya información de tipo completa está disponible en runtime.
Wildcards acotados: ? extends T / ? super T
? extends T (acotado superiormente) significa "algún tipo que es T o un subtipo de T". ? super T (acotado inferiormente) significa "algún tipo que es T o un supertipo de T". Insight clave: podés LEER de una colección ? extends T (obtenés al menos un T), pero NO podés ESCRIBIR en ella. Podés ESCRIBIR en una colección ? super T, pero obtenés Object cuando LEES. Esta asimetría es PECS.
PECS: Producer Extends, Consumer Super
PECS (Producer Extends, Consumer Super) es la regla para elegir wildcards. Usá ? extends T cuando el tipo parametrizado es un productor — estás leyendo (produciendo) valores de él. Usá ? super T cuando el tipo parametrizado es un consumidor — estás escribiendo (consumiendo) valores en él. Ejemplo: Collections.copy(List'<'? super T'>' dest, List'<'? extends T'>' src) — src produce T (extends), dest consume T (super).
Code example
// Borrado de tipos — ambas son List en runtime
List<String> strings = new ArrayList<'>();
List<Integer> ints = new ArrayList<'>();
// strings.getClass() == ints.getClass() → true!
// PECS: copiar desde productor (extends) hacia consumidor (super)
public static <T> void copy(
List<? super T> dest,
List<? extends T> src) {
for (T item : src) dest.add(item);
}
// Método genérico: funciona para cualquier tipo Comparable
public static <T extends Comparable<T>'> T max(List<T> list) {
T result = list.get(0);
for (T item : list)
if (item.compareTo(result) > 0) result = item;
return result;
}
// No se puede crear un array genérico — error de compilación:
// T[] arr = new T[10]; // ERROR: generic array creation