Menu
Coddy logo textTech

Introducción a los genéricos

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy. Lección 53 de 87.

Imagina que necesitas crear una clase que almacene un valor y lo recupere más tarde. Sin generics, tendrías que escribir clases separadas para cada tipo: una para Integer, una para String, una para Double, y así sucesivamente. Esto provoca duplicación de código y problemas de mantenimiento.

Los genéricos resuelven este problema al permitirte escribir clases y métodos que funcionan con cualquier tipo, manteniendo al mismo tiempo la seguridad de tipos. Defines un marcador de posición (llamado parámetro de tipo) que se reemplaza por un tipo concreto cuando usas la clase:

// Sin genéricos - usa Object, requiere casting
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0);  // Se necesita casting manual

// Con genéricos - type-safe, sin casting
List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0);  // No se necesita casting

Los corchetes angulares <T> denotan un parámetro de tipo. Cuando escribes List<String>, le estás indicando al compilador que esta lista solo contendrá cadenas. Si intentas añadir un entero, el compilador detecta el error inmediatamente en lugar de fallar durante la ejecución.

Los genéricos ofrecen dos beneficios clave: eliminan la necesidad de realizar conversiones de tipos explícitas y detectan los errores de tipo en tiempo de compilación en lugar de hacerlo durante la ejecución. Esto hace que tu código sea más seguro y limpio. En las siguientes lecciones, exploraremos cómo crear tus propias clases y métodos genéricos.

challenge icon

Desafío

Fácil

Construyamos un sistema de almacenamiento sencillo que demuestre el poder de los genéricos comparando la forma antigua (usando Object con conversión de tipos) con la forma nueva (usando genéricos con seguridad de tipos).

Crearás tres archivos para ver la diferencia de primera mano:

  • OldBox.java: Crea una clase que almacene valores de la forma anterior a los genéricos. Tu OldBox debe tener un campo privado content de tipo Object. Incluye un constructor que acepte un Object y lo almacene, y un método getContent() que devuelva el Object. Este enfoque funciona, pero requiere una conversión de tipos al recuperar los valores.
  • GenericBox.java: Ahora crea la versión moderna y segura en cuanto a tipos usando genéricos. Tu GenericBox debe usar un parámetro de tipo T en su declaración. Necesita un campo privado content de tipo T, un constructor que acepte un valor T y un método getContent() que devuelva el tipo T. ¡No se necesita ninguna conversión de tipos al usar esta clase!
  • Main.java: Demuestra ambos enfoques uno al lado del otro. Recibirás dos entradas: una palabra (String) y un número (entero).

    Primero, usa el enfoque antiguo: crea un OldBox que almacene la palabra, después recupérala con una conversión a String e imprime: OldBox (with cast): [value]

    A continuación, usa el enfoque genérico: crea un GenericBox<String> que almacene la misma palabra, recupérala sin conversión e imprime: GenericBox (no cast): [value]

    Después, muestra los genéricos funcionando con enteros: crea un GenericBox<Integer> que almacene el número, recupéralo e imprime: GenericBox Integer: [value]

    Finalmente, imprime una línea en blanco seguida de: Type safety: Generics catch errors at compile time!

Recibirás dos entradas en este orden: una palabra (String) y un número (entero como String, que analizarás).

Observa la diferencia clave: con OldBox, debes convertir (String) box.getContent() y esperar haber obtenido el tipo correcto. Con GenericBox, el compilador conoce el tipo y no se necesita ninguna conversión. Este es el beneficio principal de los genéricos: ¡seguridad de tipos sin las complicaciones de las conversiones!

Pruébalo tú mismo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String word = scanner.nextLine();
        int number = Integer.parseInt(scanner.nextLine());
        
        // TODO: Crea un OldBox que almacene la word
        // Retrieve with cast to String and print: "OldBox (with cast): [value]"
        
        // TODO: Crea un GenericBox<String> que almacene la word
        // Retrieve without casting and print: "GenericBox (no cast): [value]"
        
        // TODO: Create a GenericBox<Integer> storing the number
        // Retrieve and print: "GenericBox Integer: [value]"
        
        // TODO: Imprime una línea en blanco, luego imprime:
        // "Type safety: Generics catch errors at compile time!"
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Java online