Menu
CoddyTech

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 adelante. Sin genéricos, 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 dolores de cabeza a la hora de mantenerlo.

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

// Sin genéricos: usa Object y requiere una conversión de tipos
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0);  // Se necesita una conversión de tipos manual

// Con genéricos: seguridad de tipos, sin conversión de tipos
List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0);  // No se necesita conversión de tipos

Los corchetes angulares <T> indican un parámetro de tipo. Cuando escribes List<String>, le indicas al compilador que esta lista solo contendrá cadenas. Si intentas añadir un entero, el compilador detecta el error de inmediato en lugar de que se produzca un fallo durante la ejecución.

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

challenge icon

Desafío

Fácil

Vamos a crear 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 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 al estilo 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 convertir el tipo al recuperar 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 tipo 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, luego recupérala convirtiendo el tipo 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 convertir el tipo e imprime: GenericBox (no cast): [value]

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

    Por último, 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 el tipo con (String) box.getContent() y esperar haber obtenido el tipo correcto. Con GenericBox, el compilador conoce el tipo y no hace falta convertirlo. Esta es la ventaja fundamental 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 palabra
        // Recupera el valor con una conversión a String e imprime: "OldBox (with cast): [value]"
        
        // TODO: Crea un GenericBox<String> que almacene la palabra
        // Recupera el valor sin conversión de tipo e imprime: "GenericBox (no cast): [value]"
        
        // TODO: Crea un GenericBox<Integer> que almacene el número
        // Recupera el valor e imprime: "GenericBox Integer: [value]"
        
        // TODO: Imprime una línea en blanco y 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