Ejemplo de la importancia
Queremos crear un método en la clase Ordenar para implementar el método de ordenamiento de burbuja que ordene de mayor a menor una lista de objetos de cualquier clase.
Uso de tipos genéricos
En primer lugar, vamos a resolver el problema usando tipos genéricos. Por lo tanto, definimos e implementamos el método MetodoBurbuja donde el contenido de la lista es del tipo genérico T:
class Ordenar {
public static <T> void MetodoBurbuja(ArrayList<T> lista) {
boolean ordenada = false;
while (!ordenada) {
ordenada = true;
for (int i = 0; i < lista.size() - 1; i++) {
// En esta comparación necesitamos comparar si lista.get(i+1)
// es mayor que lista.get(i) para hacer el intercambio
if (/* Debemos introducir una condición aquí */) {
T aux = lista.get(i);
lista.set(i, lista.get(i + 1));
lista.set(i + 1, aux);
ordenada = false;
}
}
}
}
}
En la condición del if necesitamos poder realizar una comparación entre dos objetos de la clase genérica T. Como desconocemos cómo es la clase T, no sabemos cómo se va a hacer esa comparación.
Para solucionar este problema, podemos crear la interfaz Comparar. Esta sólo definirá un método esMayor para saber cuál es el mayor de dos objetos del tipo genérico T:
interface Comparar<T> {
boolean esMayor(T objeto);
}
Ahora sólo debemos modificar nuestro método MetodoBurbuja para que admita únicamente clases que implementen la interfaz Comparar<T> y utilizar el método esMayor para comparar los dos objetos de la clase genérica T:
class Ordenar {
// Estamos diciendo con extends que T tiene que implementar Comparar<T>
public static <T extends Comparar<T>> void MetodoBurbuja(ArrayList<T> lista) {
boolean ordenada = false;
while (!ordenada) {
ordenada = true;
for (int i = 0; i < lista.size() - 1; i++) {
// Ahora podemos comparar dos objetos
if (lista.get(i + 1).esMayor(lista.get(i))) {
T aux = lista.get(i);
lista.set(i, lista.get(i + 1));
lista.set(i + 1, aux);
ordenada = false;
}
}
}
}
}
Ahora para cualquier clase que creemos, si esta implementa Comparar<T> podremos ordenarla de mayor a menor utilizando nuestro método estático MetodoBurbuja.
Uso de polimorfismo
Podemos modificar para utilizar polimorfismo en lugar de tipos genéricos.
Para empezar modificamos la interfaz <Comparar> para que en el método esMayor reciba como parámetro un objeto de tipo Comparar.
interface Comparar {
boolean esMayor(Comparar objeto);
}
Ahora donde utilizamos polimorfismo es en el método MetodoBurbuja:
import java.util.ArrayList;
interface Comparar {
boolean esMayor(Comparar objeto);
}
class Ordenar {
public static void MetodoBurbuja(ArrayList<Comparar> lista) {
boolean ordenada = false;
while (!ordenada) {
ordenada = true;
for (int i = 0; i < lista.size() - 1; i++) {
if (lista.get(i + 1).esMayor(lista.get(i))) {
Comparar aux = lista.get(i);
lista.set(i, lista.get(i + 1));
lista.set(i + 1, aux);
ordenada = false;
}
}
}
}
}
Comparativa
En la siguiente tabla comparamos las dos implementaciones del método MetodoBurbuja:
- La versión con tipos genéricos.
- La versión sin tipos genéricos (uso de polimorfismo).
| Criterio | Con tipos genéricos (<T extends Comparar<T>>) | Sin tipos genéricos (ArrayList<Comparar>) |
|---|---|---|
| Seguridad en compilación | ✅ Más seguro, evita errores de tipo en tiempo de ejecución. | ❌ Menos seguro, puede haber ClassCastException. |
| Flexibilidad | ✅ Funciona con cualquier clase que implemente Comparar<T>. | ❌ La lista puede contener objetos de distintos tipos, lo que puede generar errores. |
| Reutilización del código | ✅ Puede ser usado con diferentes clases sin cambios. | ❌ Puede ser menos reutilizable si los tipos no son compatibles. |
| Claridad y simplicidad | ❌ Más complejo al definir los tipos genéricos. | ✅ Más simple, evita la sintaxis de tipos genéricos. |
| Facilidad de mantenimiento | ✅ Más flexible y fácil de modificar en proyectos grandes. | ❌ Puede ser más difícil de depurar si hay errores de tipo. |