Clases Genéricas en Java

Introducción a las Clases Genéricas en Java

En Java, las clases genéricas son una herramienta poderosa que permite escribir código más flexible y reutilizable. En lugar de escribir múltiples versiones de una clase para diferentes tipos de datos, las clases genéricas nos permiten trabajar con cualquier tipo, manteniendo la seguridad del tipo y evitando errores comunes en tiempo de ejecución.

En esta guía aprenderás:

  • Qué son las clases genéricas.
  • Cómo y por qué utilizarlas.
  • Ejemplos prácticos.
  • Buenas prácticas para su uso.

¿Qué son las Clases Genéricas?

Una clase genérica es una clase que usa un tipo de dato como parámetro. Esto significa que puedes crear una clase que funcione con cualquier tipo de dato, sin especificar el tipo exacto en el momento de escribirla. El tipo se define cuando creas una instancia de la clase.

Sintaxis Básica

class NombreClase<T> {
    // Aquí T representa un tipo genérico
}

  • T es un parámetro de tipo genérico. Puede ser cualquier letra, pero por convención se usa:
    • T para «Type».
    • E para «Element» (en colecciones).
    • K y V para claves y valores en mapas.

¿Por qué Usar Clases Genéricas?

1. Reutilización del Código

En lugar de escribir varias versiones de una clase para diferentes tipos de datos, puedes usar una única clase genérica.

2. Seguridad del Tipo

Las clases genéricas aseguran que los tipos de datos sean consistentes, reduciendo errores de conversión.

3. Facilidad de Mantenimiento

Si necesitas cambiar la lógica, solo tienes que hacerlo en una clase, no en múltiples versiones.


Ejemplo Práctico: Clase Genérica Básica

Vamos a crear una clase genérica llamada Caja que puede almacenar cualquier tipo de objeto.

Código:

class Caja<T> {
    private T contenido;

    public void setContenido(T contenido) {
        this.contenido = contenido;
    }

    public T getContenido() {
        return contenido;
    }
}

Uso:

public class Main {
    public static void main(String[] args) {
        // Caja para almacenar un String
        Caja<String> cajaString = new Caja<>();
        cajaString.setContenido("Hola, mundo");
        System.out.println("Contenido de la caja: " + cajaString.getContenido());

        // Caja para almacenar un Integer
        Caja<Integer> cajaInteger = new Caja<>();
        cajaInteger.setContenido(123);
        System.out.println("Contenido de la caja: " + cajaInteger.getContenido());
    }
}

Salida:

Contenido de la caja: Hola, mundo
Contenido de la caja: 123


Clases Genéricas con Varios Parámetros de Tipo

Puedes definir más de un tipo genérico en una clase. Por ejemplo, vamos a crear un Par que almacene dos objetos de diferentes tipos.

Código:

class Par<K, V> {
    private K clave;
    private V valor;

    public Par(K clave, V valor) {
        this.clave = clave;
        this.valor = valor;
    }

    public K getClave() {
        return clave;
    }

    public V getValor() {
        return valor;
    }
}

Uso:

public class Main {
    public static void main(String[] args) {
        Par<String, Integer> par = new Par<>("Edad", 25);
        System.out.println("Clave: " + par.getClave());
        System.out.println("Valor: " + par.getValor());
    }
}

Salida:

Clave: Edad
Valor: 25


Restricciones en los Tipos Genéricos

Puedes limitar los tipos que una clase genérica puede aceptar usando bounded types.

Ejemplo: Clase Genérica con Restricción

class CajaNumerica<T extends Number> {
    private T numero;

    public void setNumero(T numero) {
        this.numero = numero;
    }

    public T getNumero() {
        return numero;
    }

    public double getDoble() {
        return numero.doubleValue() * 2;
    }
}

Uso:

public class Main {
    public static void main(String[] args) {
        CajaNumerica<Integer> cajaEntero = new CajaNumerica<>();
        cajaEntero.setNumero(10);
        System.out.println("Número: " + cajaEntero.getNumero());
        System.out.println("Doble: " + cajaEntero.getDoble());

        CajaNumerica<Double> cajaDecimal = new CajaNumerica<>();
        cajaDecimal.setNumero(5.5);
        System.out.println("Número: " + cajaDecimal.getNumero());
        System.out.println("Doble: " + cajaDecimal.getDoble());
    }
}

Salida:

Número: 10
Doble: 20.0
Número: 5.5
Doble: 11.0


Métodos Genéricos

No solo las clases pueden ser genéricas; también puedes crear métodos genéricos.

Ejemplo:

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

Uso:

public class Main {
    public static void main(String[] args) {
        String[] palabras = {"Hola", "Mundo", "Genérico"};
        Integer[] numeros = {1, 2, 3, 4, 5};

        Utilidades.imprimirArray(palabras);
        Utilidades.imprimirArray(numeros);
    }
}

Salida:

Hola Mundo Genérico 
1 2 3 4 5 


Buenas Prácticas con Clases Genéricas

  1. Usa Nombres Descriptivos:
    • Aunque T, E, K, y V son comunes, usa nombres más claros si el contexto lo requiere.
  2. No Abuses de los Genéricos:
    • Si una clase no necesita ser genérica, no la hagas genérica.
  3. Combina Genéricos con Herencia:
    • Puedes usar genéricos en combinación con clases y métodos heredados.
  4. Documenta las Restricciones:
    • Asegúrate de documentar bien los límites (extends) para evitar confusiones.

Ejercicios Propuestos

  1. Clase Genérica Par:
    • Implementa una clase Par que almacene dos valores genéricos y permite intercambiarlos con un método intercambiar().
  2. Clase CajaNumerica:
    • Extiende la clase CajaNumerica para incluir un método esMayorQue(CajaNumerica<T> otra) que compare los valores.
  3. Método Genérico:
    • Crea un método genérico que busque un elemento en un array y devuelva su índice.
  4. Restricción de Tipos:
    • Implementa una clase genérica Comparador<T> que solo acepte tipos que implementen Comparable.

Conclusión

Las clases genéricas son una herramienta esencial en Java que te permiten escribir código más flexible, seguro y reutilizable. Ahora que conoces los conceptos básicos y avanzados, ¡es tu turno de ponerlos en práctica! 🖥️


Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.