Porqué a veces es mejor usar <? super T> y no simplemente <T>
24 de noviembre de 2023 - Matias Bagini
Para insertar objetos en TreeSets o utilizarlos como claves en TreeMaps, entre otras cuestiones, es necesario implementar la interfaz Comparable (a menos que se explicite un Comparator). La interfaz Comparable es parametrizada :
public interface Comparable This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.
Esta interfaz requiere implementar un único método: int compareTo(T o) Entonces, si tengo una clase Persona, con atributo id, y quiero ordenar por ese criterio, puedo implementar: public int compareTo(Persona p) { return Integer.compare(this.id, p.id); } Ahora supongamos que quiero crear una colleccion llamada MiColeccion que guarde elementos ordenados y extienda TreeSet. Podría hacer algo como: public MiColeccion extends TreeSet {} Como TreeSet es una clase genérica, debería hacer también genérica la mía y colocar : public MiColeccion extends TreeSet {} Si defino mi colección de esta forma, puedo insertar objetos que no implementen Comparable, y (de no explicitar un Comparator) obtendré un error en tiempo de ejecución. public void main(String[] args) { MiCollection personas = new MiCollection<>(); personas.add(new Persona(1234)); // OK porque Persona implementa Comparable MiCollection archivos = new MiCollection<>(); archivos.add(new File("archivo.txt")) // ERROR porque File no implementa Comparable } #imagenConError Entonces, para programar más defensivamente puedo obligar a que los objetos que se inserten implementen Comparable: public MiColeccionextends Comparable> extends TreeSet {} Como Comparable es una clase genérica también, la forma correcta sería indicar: public MiColeccionextends Comparable> extends TreeSet De esta forma, volviendo al ejemplo anterior, la instrucción MiCollection va a fallar en tiempo de compilación: INDICAR ERROR DE COMPILACION, evitando errores futuros. public void main(String[] args) { MiCollection personas = new MiCollection<>(); personas.add(new Persona(1234)); // OK porque Persona implementa Comparable MiCollection archivos = new MiCollection<>(); archivos.add(new File("archivo.txt")) // ERROR porque File no implementa Comparable } Pero qué pasa si decido extender la clase Persona, por ejemplo creando la clase Alumno? public class Alumno extends Persona {}
  • Puedo crear una colección MiCollection?
  • Alumno implementa Comparable?
Así cómo definimos las clases, Alumno implementa Comparable porque extiende de Persona. Pero implementa Comparable. La definición > nos obliga a que la clase X implemente Comparable, o que Alumno implemente Comparable Por lo que vamos a tener error en tiempo de compilación: MOSTRAR IMAGEN ERROR Entonces nos veríamos obligados a redefinir la clase Alumno como: public class Alumno extends Persona implements Comparable { public int compareTo(Alumno a) { return super.compareTo(a); } } Lamentablemente tendríamos que reimplementar el método compareTo en cualquier clase que la extienda. Para evitar esto, podemos cambiar la definición de MiColeccion. En vez de Comparable, pediremos que los objetos que se insertan implementen Comparable: public MiColeccionextends Comparable> extends TreeSet Al hacer esta modificación, puedo insertar objetos de tipo Alumno, aunque esa clase no implemente Comparable. La expresión Comparable> nos indica que puede implementar Comparable "? super T". O sea, cualquier Clase que sea super de T (padre de T).

Relacionados

ESEN