Generics en Java: para qué sirven y cómo usarlos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Generics en Java: para qué sirven y cómo usarlos



Generics (genéricos) — una de las capacidades clave del lenguaje Java, introducida en la versión J2SE 5.0. Permiten crear clases, interfaces y métodos que trabajan con diferentes tipos de datos, manteniendo una tipificación estricta en la etapa de compilación. En este artículo analizaremos para qué sirven los genéricos, cómo usarlos correctamente y qué errores ayudan a evitar.



¿Para qué sirven los Generics en Java?



Antes de la aparición de los genéricos, los programadores usaban conversión de tipos (casting) y trabajaban con Object. Esto generaba dos problemas principales:



  • Falta de seguridad de tipos — se podía agregar cualquier tipo de objeto a una colección, y el error solo se manifestaba en tiempo de ejecución.
  • Necesidad de conversión explícita — al extraer un elemento de la colección se requería un cast, lo que saturaba el código.


// Sin Generics (Java anterior a 5)List list = new ArrayList();list.add("cadena");list.add(123); // Error no en etapa de compilaciónString s = (String) list.get(0); // Hay que convertir explícitamente


// Con GenericsList<String> list = new ArrayList<>();list.add("cadena");// list.add(123); // ¡Error de compilación!String s = list.get(0); // No se necesita conversión


Principales ventajas de Generics:

  • Seguridad de tipos — los errores de tipo se detectan en la etapa de compilación.
  • Eliminación de conversiones explícitas — el código se vuelve más limpio y legible.
  • Reutilización de código — una misma implementación funciona con diferentes tipos.


Creación de clases y métodos genéricos



Clase genérica



Para crear una clase que funcione con un tipo arbitrario, basta con indicar el parámetro de tipo entre corchetes angulares después del nombre de la clase:



public class Box<T> {    private T content;

public void setContent(T content) { this.content = content; }

public T getContent() { return content; }

public static void main(String[] args) { Box<String> stringBox = new Box<>(); stringBox.setContent("¡Hola, Java!"); System.out.println(stringBox.getContent());

Box<Integer> intBox = new Box<>(); intBox.setContent(42); System.out.println(intBox.getContent()); }}


En este ejemplo, T es el parámetro de tipo. Al crear el objeto Box<String>, todas las ocurrencias de T se reemplazan por String.



Método genérico



Los métodos también pueden ser parametrizados. El parámetro de tipo se indica antes del tipo de retorno:



public class Util {    public static <T> void printArray(T[] array) {        for (T element : array) {            System.out.print(element + " ");        }        System.out.println();    }

public static void main(String[] args) { Integer[] intArray = {1, 2, 3, 4, 5}; String[] strArray = {"A", "B", "C"};

printArray(intArray); // 1 2 3 4 5 printArray(strArray); // A B C }}


Observe: el parámetro de tipo <T> va antes de void. Esto es obligatorio para métodos genéricos.



Tipos acotados (Bounded Type Parameters)



A veces es necesario limitar qué tipos pueden usarse como parámetro. Para esto se utilizan las palabras clave extends y super.



Límite superior (extends)



Limita el tipo por arriba — solo se puede usar la clase indicada o sus subclases:



public class Calculator<T extends Number> {    private T value;

public Calculator(T value) { this.value = value; }

public double square() {

Blogs

Book Recommendations