通用方法和通配符

时间:2012-03-17 22:39:06

标签: java generics covariance contravariance bounded-wildcard

以下三个签名之间有什么区别?

static <T> void foo(List<T>,           Comparator<? super T>);
static <T> void bar(List<? extends T>, Comparator<T>        );
static <T> void baz(List<? extends T>, Comparator<? super T>);

我知道Generics中extendssuper的含义。我的问题是foobarbaz之间是否存在差异。我是否应该使其中一个参数保持不变,另一个变量在适当的方向上,或者我应该使它们两个变体?它有所作为吗?

3 个答案:

答案 0 :(得分:5)

PECS - Producer扩展,消费者超级。

解释这个“规则”:

  • extends表示通用化对象生成该类型的元素。当它是一个集合时,它意味着你只能从集合中获取元素,但不能将它们放入。比较器
  • super表示对象使用所选类型的对象。因此,您可以添加到集合中,但不能从中读取。
  • 缺少扩展和超级意味着您可以为指定的确切类型执行这两种操作。

关于Comparator,我认为这没有任何区别。通常,它会是<? super T>,因为比较器使用对象,但在所有三种情况下,您都可以安全地调用Collections.sort(list, comparator);(其签名为<? super T>

答案 1 :(得分:2)

唯一的区别是T是否代表List的类型参数,Comparator或其中的某些内容。

就调用者而言,三种方法签名是等效的,即只要其中一个可以使用,其他签名也可以使用。

对于方法实现foo可能是最方便的,因为它允许修改列表而无需额外的捕获转换,这需要委托给辅助方法。

答案 2 :(得分:1)

我认为? extends T表示List可能是从T派生的任何类型的通用,而List<T>只能是List T而不是任何派生类。