我正在阅读java源代码,我发现如下:
http://www.java2s.com/Code/JavaAPI/java.util/newTreeSetEComparatorsuperEc.htm
我不明白为什么这个构造函数的参数是<? super E>
。
根据我的理解,它应该是<? extend E>
而不是<? super E>
,因为如果E具有可比性,则E的子女必须具有可比性,而E的父母可能不具有可比性。
答案 0 :(得分:14)
我们考虑三个类:Drink
,Juice extends Drink
和OrangeJuice 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>
创建一组香蕉。但这不起作用:干香蕉的比较只能比较干香蕉。不是所有种类的香蕉。
答案 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
的任何子类,例如StringBuilder
,CharBuffer
等等...
如果CharSequence
不是abstract
,它也可以包含它们的实例。
通过这个例子,我们理解概念上Comparator<? extend E>
是错误的。