java - ordering - Declaración de Collections.sort(): ¿por qué<? super T> en lugar de<T>
short collection java (3)
Se diferencian porque ? super T
? super T
es menos restrictivo que T
Es un comodín de límite inferior (el Tutorial de Java vinculado dice, en parte)
El término
List<Integer>
es más restrictivo queList<? super Integer>
List<? super Integer>
porque el primero coincide con una lista de tipoInteger
solamente, mientras que el último coincide con una lista de cualquier tipo que es un supertipo deInteger
.
Reemplace Integer
con T
y significa una T
o un java.lang.Object
.
¿Por qué Collections.sort(List<T>)
tiene la firma:
public static <T extends Comparable<? super T>> void sort(List<T> list)
y no :
public static <T extends Comparable<T>> void sort(List<? extends T> list)
- Entiendo que ambos servirían para el mismo propósito; Entonces, ¿por qué los desarrolladores del framework usaron la primera opción?
- ¿O son estas declaraciones realmente diferentes?
Su firma propuesta probablemente funcionaría en Java-8. Sin embargo, en las versiones anteriores de Java, la inferencia de tipos no era tan inteligente. Tenga en cuenta que tiene la List<java.sql.Date>
. Tenga en cuenta que java.sql.Date
amplía java.util.Date
que implementa Comparable<java.util.Date>
. Cuando compilas
List<java.sql.Date> list = new ArrayList<>();
Collections.sort(list);
Funciona perfectamente en Java-7. Aquí se infiere que T
es java.sql.Date
que es en realidad Comparable<java.util.Date>
Comparable<? super java.sql.Date>
que es Comparable<? super java.sql.Date>
Comparable<? super java.sql.Date>
. Sin embargo, vamos a probar su firma:
public static <T extends Comparable<T>> void sort(List<? extends T> list) {}
List<java.sql.Date> list = new ArrayList<>();
sort(list);
Aquí T
debe inferirse como java.util.Date
. Sin embargo, la especificación de Java 7 no permite tal inferencia. Por lo tanto, este código se puede compilar con Java-8, pero falla cuando se compila bajo Java-7:
Main.java:14: error: method sort in class Main cannot be applied to given types;
sort(list);
^
required: List<? extends T>
found: List<Date>
reason: inferred type does not conform to declared bound(s)
inferred: Date
bound(s): Comparable<Date>
where T is a type-variable:
T extends Comparable<T> declared in method <T>sort(List<? extends T>)
1 error
La inferencia de tipos se mejoró enormemente en Java-8. El capítulo 18 separado de JLS está dedicado a él ahora, mientras que en Java-7 las reglas were mucho más simples.
// 0
public static <T extends Comparable<? super T>> void sort0(List<T> list)
// 1
public static <T extends Comparable<T>> void sort1(List<? extends T> list)
Estas firmas difieren porque imponen requisitos diferentes en la relación entre el tipo T
y el argumento de tipo Comparable
en la definición de T
Supongamos, por ejemplo, que tiene esta clase:
class A implements Comparable<Object> { ... }
Entonces si tienes
List<A> list = ... ;
sort0(list); // works
sort1(list); // fails
La razón por la que sort1
falla es que no hay un tipo T
que sea comparable a sí mismo y que sea, o sea un supertipo de, el tipo de la lista.
Resulta que la clase A
tiene un formato incorrecto, porque los objetos que son Comparable
deben cumplir ciertos requisitos. En particular, revertir la comparación debería revertir el signo del resultado. Podemos comparar una instancia de A
con un Object
pero no al revés, por lo que se viola este requisito. Pero tenga en cuenta que este es un requisito de la semántica de Comparable
y no está impuesto por el sistema de tipos. Teniendo en cuenta únicamente el sistema de tipos, las dos declaraciones de sort
son realmente diferentes.