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 castingLos 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.
Desafío
FácilConstruyamos 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 privadocontentde tipoObject. Incluye un constructor que acepte un Object y lo almacene, y un métodogetContent()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 tipoTen su declaración. Necesita un campo privadocontentde tipoT, un constructor que acepte un valorTy un métodogetContent()que devuelva el tipoT. ¡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!"
}
}
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
1Fundamentos de OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón IteratorPractica por tu cuenta: Compilador de Java online