我注意到了Collections.sort的具体说明:
public static <T> void sort(List<T> list, Comparator<? super T> c)
为什么这里需要“? super
”?如果ClassB
延伸ClassA
,那么我们无法保证Comparator<ClassA>
能够比较两个ClassB
个对象,而不是“? super
“部分?
换句话说,鉴于此代码:
List<ClassB> list = . . . ;
Comparator<ClassA> comp = . . . ;
Collections.sort(list, comp);
为什么编译器不够聪明,即使没有为Collections.sort()声明指定“? super
”,也不知道这是否正常?
答案 0 :(得分:7)
Josh Bloch今年在谷歌I / O上发表了一个名为Effective Java Reloaded的演讲,您可能会感兴趣。它讨论了一个名为“Pecs”(生产者extends
,消费者super
)的助记符,它解释了为什么在输入参数中使用? extends T
和? super T
(仅限;永远不会返回类型),以及何时使用。
答案 1 :(得分:6)
More Fun with Wildcards中有一个非常好(但有点曲折)的解释。
答案 2 :(得分:1)
这与C#类似,我刚刚了解了它为什么(困难的方式,然后是PDC信息方式)。
假设Dog extends Animal
Blah<Dog>
不与Blah<Animal>
相同,即使Dog
扩展Animal
,它们的类型签名也完全不同。
例如假设Blah<T>
上的方法:
T Clone();
Blah<Dog>
Dog Clone();
Blah<Animal>
Animal Clone();
这是Blah<Dog>
。
您需要一种方法来区分编译器可以说Blah<Animal>
具有相同的<? super T>
公共接口,而Blah<? super T>
表示 - 任何用作T的类都可以缩减为它的超级等级Blah<out T>
。
(在C#4.0中,我相信这将是{{1}}。)
答案 3 :(得分:0)
对你来说很明显,在Comparator
的情况下,任何T
的祖先都会起作用。但是编译器不知道类Comparator
的功能是这样的 - 只需要告诉它是否应该允许<T>
或<? super T>
。
从另一个角度来看,是的,在这种情况下,祖先的任何Comparator
都可以正常工作 - 而且库开发人员说这是使用<? super T>
的方式。
答案 4 :(得分:0)
您的问题的简单答案是图书馆设计师希望为图书馆的用户提供最大的灵活性;例如,此方法签名允许您执行以下操作:
List<Integer> ints = Arrays.asList(1,2,3);
Comparator<Number> numberComparator = ...;
Collections.sort(ints, numberComparator);
使用通配符可以防止您被强制使用Comparator<Integer>
;该语言要求图书馆设计者指定通配符这一事实使他或她能够允许或限制此类使用。