Estoy leyendo el código fuente de Java y he encontrado las siguientes cosas:
http://www.java2s.com/Code/JavaAPI/java.util /newTreeSetEComparatorsuperEc.htm

No entiendo por qué el parámetro de este constructor es <? super E>.

Según tengo entendido, debería ser <? extend E> en lugar de <? super E> porque si E es comparable, los hijos de E deben ser comparables, mientras que los padres de E pueden no serlo.

9
Yves 22 oct. 2017 a las 17:43

3 respuestas

La mejor respuesta

Consideremos tres clases: Drink, Juice extends Drink y OrangeJuice extends Juice.

Si quiero un TreeSet<Juice>, necesito un comparador que compare dos jugos. Por supuesto, un Comparator<Juice> hará esto.

Un Comparator<Drink> también hará esto, porque puede comparar dos bebidas y, por lo tanto, dos jugos.

A Comparator<OrangeJuice> no hará esto. Si quisiera agregar un AppleJuice a mi conjunto de jugos, eso no es compatible con este comparador, ya que solo puede comparar jugos de naranja.

14
Joe C 22 oct. 2017 a las 14:49

debería ser en lugar de porque si E es comparable, los hijos de E deben ser comparables, mientras que los padres de E pueden no serlo.

Comparator no se basa en objetos Comparable.
Incluso se usa a menudo como alternativa o complemento.

De hecho, esta constructora

public TreeSet(Comparator<? super E> comparator) {...}

Podría haber sido :

public TreeSet(Comparator<E> comparator) {... }

Pero al especificar un comodín acotado inferior, los desarrolladores de JDK proporcionaron más flexibilidad para las clases de clientes al permitir que Comparator sea interoperable con las instancias de clase actuales y las instancias de clase principal. En algunos casos, puede tener sentido.

Ahora esto :

public TreeSet(Comparator<? extend E> comparator) {

No puede ser válido ya que significa que puede terminar con un método compare() que especifica el tipo de subclase como parámetros.
Pero los elementos de Set pueden contener instancias de una subclase específica, pero no solo.

Imagina este código:

TreeSet<CharSequence> set = new TreeSet<>(new Comparator<String>() {

    @Override
    public int compare(String o1, String o2) {
        ...
    }
});

set.add("string");
set.add(new StringBuilder());
...

Quiero comparar String s, pero Set podría contener String instancias, pero también cualquier subclase de CharSequence como StringBuilder, CharBuffer, etc. ..
Y si CharSequence no era abstract, también podría contener instancias de ellos.

Con este ejemplo, entendemos que conceptualmente Comparator<? extend E> está mal.

4
davidxxx 22 oct. 2017 a las 15:42

Creas un conjunto ordenado de plátanos. Para hacer eso, debes poder comparar los plátanos. Por lo tanto, puede usar un comparador de plátanos para hacer eso. Pero si tiene un comparador que puede clasificar cualquier tipo de fruta (incluidas las bananas), entonces eso también funcionará. Por lo tanto, también puede usar un Comparator<Fruit> o incluso un Comparator<Food> para clasificar sus plátanos.

Es por eso que se utiliza un Comparator<? super E>.

Si fuera Comparator<? extends E>, podría crear un conjunto de plátanos con un Comparator<DriedBanana>. Pero eso no funcionaría: un comparador de plátanos secos solo puede comparar plátanos secos. No todo tipo de plátanos.

Para obtener más información, lea también ¿Qué es PECS (Producer Extends Consumer Super)?

7
JB Nizet 22 oct. 2017 a las 14:48