为什么TreeSet <e>的构造函数接受E的参数super而不是E

时间:2017-10-22 14:43:15

标签: java comparator

我正在阅读java源代码,我发现如下:
http://www.java2s.com/Code/JavaAPI/java.util/newTreeSetEComparatorsuperEc.htm

我不明白为什么这个构造函数的参数是<? super E>

根据我的理解,它应该是<? extend E>而不是<? super E>,因为如果E具有可比性,则E的子女必须具有可比性,而E的父母可能不具有可比性。

3 个答案:

答案 0 :(得分:14)

我们考虑三个类:DrinkJuice extends DrinkOrangeJuice extends Juice

如果我想要一个TreeSet<Juice>,我需要一个可比较任何两种果汁的比较器。当然Comparator<Juice>会这样做。

Comparator<Drink>也会这样做,因为它可以比较任何两种饮料,因此可以比较任何两种果汁。

Comparator<OrangeJuice>不会这样做。如果我想在我的果汁组中添加AppleJuice,那就与这个比较器不兼容,因为它只能比较橙汁。

答案 1 :(得分:7)

您创建一组有序的香蕉。要做到这一点,你需要能够比较香蕉。因此,您可以使用香蕉比较器来做到这一点。但如果你有一个可以对任何种类的水果(包括香蕉)进行分类的比较物,那么它也会起作用。因此,您还可以使用Comparator<Fruit>甚至Comparator<Food>对香蕉进行排序。

这就是使用Comparator<? super E>的原因。

如果是Comparator<? extends E>,您就可以使用Comparator<DriedBanana>创建一组香蕉。但这不起作用:干香蕉的比较只能比较干香蕉。不是所有种类的香蕉。

有关详情,请阅读What is PECS (Producer Extends Consumer Super)?

答案 2 :(得分:4)

  

它应该是,而不是因为如果是   相比之下,E的孩子必须与父母相当   E可能不是。

Comparator不依赖Comparable个对象 它甚至经常被用作替代或补充。

实际上,这个构造函数

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

可能是:

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

但是通过指定较低的有界通配符,JDK开发人员允许Comparator与当前类实例和父类实例互操作,从而为客户端类提供了更大的灵活性。在某些情况下,它可能有意义。

现在这个:

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

无效,因为这意味着您可以使用compare()方法完成,该方法将子类类型指定为参数。
但是Set的元素可能包含特定子类的实例,但不仅仅包含。(

想象一下这段代码:

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

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

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

我想比较String,但Set可能包含String个实例,但也包含CharSequence的任何子类,例如StringBuilderCharBuffer等等...
如果CharSequence不是abstract,它也可以包含它们的实例。

通过这个例子,我们理解概念上Comparator<? extend E>是错误的。