Generics en Java: para qué sirven y cómo usarlos para principiantes
\n\nSi apenas estás comenzando a estudiar Java, tarde o temprano te encontrarás con el concepto de Generics (tipos parametrizados o genéricos). Esta poderosa característica del lenguaje permite escribir código más flexible, seguro y reutilizable. En este artículo explicaremos de forma sencilla qué son los Generics, para qué sirven y cómo aplicarlos en la práctica.
\n\n¿Qué son los Generics en Java?
\n\nGenerics (del inglés "generic" — genérico, común) es un mecanismo de Java que permite crear clases, interfaces y métodos que trabajan con diferentes tipos de datos, pero garantizando una verificación estricta de tipos en tiempo de compilación.
\n\nEn pocas palabras, los genéricos permiten indicar: "Esta clase o método funcionará con cualquier tipo de dato, pero aún no sé con cuál exactamente". El tipo se determina más tarde, cuando creas un objeto o llamas al método.
\n\nEl problema sin Generics
\n\nAntes de la llegada de los Generics (en Java 5), los desarrolladores usaban conversiones de tipos y trabajaban con Object. Esto era incómodo y peligroso:
// Sin Generics (estilo antiguo)\nList list = new ArrayList();\nlist.add("Hola");\nlist.add(123); // ¿Error? No, el compilador lo permite\n\nString text = (String) list.get(0); // Conversión obligatoria\n// String num = (String) list.get(1); // ClassCastException en tiempo de ejecución!\n\nAquí el compilador no detecta el error, pero el programa fallará en tiempo de ejecución. Los Generics resuelven este problema.
\n\n¿Para qué sirven los Generics en Java?
\n\nLos Generics aportan tres ventajas clave:
\n\n- \n
- Seguridad de tipos (Type Safety) — los errores se detectan en tiempo de compilación, no durante la ejecución del programa. \n
- Eliminación de conversiones explícitas (No Casting) — no es necesario escribir
(String)cada vez. \n - Reutilización de código (Code Reuse) — una misma clase o método puede funcionar con diferentes tipos. \n
Ejemplo con Generics
\n\nObserva cómo cambia el código al usar genéricos:
\n\n// Con Generics\nList<String> list = new ArrayList<>();\nlist.add("Hola");\n// list.add(123); // ¡Error de compilación! No se puede agregar un Integer\n\nString text = list.get(0); // No se necesita conversión\n// El compilador ya sabe que es un String\n\nEl código se vuelve más simple, seguro y legible.
\n\nCómo usar Generics: construcciones principales
\n\nAnalicemos las tres formas principales de aplicar los genéricos: en clases, métodos e interfaces.
\n\n1. Clases genéricas
\n\nPuedes crear una clase que funcione con cualquier tipo. Para ello, después del nombre de la clase, entre corchetes angulares, se indica el parámetro de tipo (generalmente T, E, K, V):
// Clase genérica "Caja"\npublic class Box<T> {\n private T content;\n\n public void put(T item) {\n this.content = item;\n }\n\n public T get() {\n return content;\n }\n}\n\n// Uso\nBox<String> stringBox = new Box<>();\nstringBox.put("Libro");\nString book = stringBox.get(); // Sin conversión\n\nBox<Integer> intBox = new Box<>();\nintBox.put(42);\nint number = intBox.get();\n\n2. Métodos genéricos
\n\nSe puede hacer genérico no toda la clase, sino solo un método específico. Esto es útil cuando el método debe procesar diferentes tipos independientemente de la clase:
\n\npublic class Utils {\n // Método genérico\n public static <T> void printArray(T[] array) {\n for (T element : array) {\n System.out.print(element + " ");\n }\n System.out.println();\n }\n}\n\n// Llamada\nInteger[] intArray = {1, 2, 3};\nString[] strArray = {"A", "B", "C"};\n\nUtils.printArray(intArray); // 1 2 3\nUtils.printArray(strArray); // A B C\n\n3. Interfaces genéricas
\n\nInterfaz