Java:使用时,列表的通用类型参数是协变还是协变?

Bon*_*i69 5 java generics lambda covariance contravariance

我对协方差和相反性有些困惑。我们是否说过,在Java中,当我们使用时通常是矛盾的? super X

现在阅读我的书,我理解了以下概念:

这是矛盾的:

method(Predicate<? super X> pred)
Run Code Online (Sandbox Code Playgroud)

但这是协变的:

method(List<? super X> list)  //And then we use add for a list of course
Run Code Online (Sandbox Code Playgroud)

这个概念没有明确地写成我要问你的方式,所以我想知道,这个定义正确吗?如果是,为什么第一个是协变的,为什么最后一个是协变的(如果两者都使用super关键字)?

Did*_*r L 0

我们不经常谈论 Java 中的方差,人们通常只应用PECS

\n

您的两个示例在方差方面是相同的,因为内部的实际方法定义是什么PredicateList评估其方差并不重要。

\n

那么这里是什么?

\n

好吧,让 \xe2\x80\x99s 说我们有Cat extends Animalmethod(List<? super Cat> list)(或与 相同Predicate)。此方法将接受List<? super Cat>List<Cat>List<Animal>甚至List<? super AnimalList<Object>作为参数,即List其泛型类型是 的超类型Cat

\n

使用符号\xe2\x89\xa4另请参阅此答案),我们看到? super反转关系:Cat \xe2\x89\xa4 Animal暗示List<Animal> \xe2\x89\xa4 List<? super Cat>,因此这是交换类型时的逆变。

\n

相反,List<Cat> \xe2\x89\xa4 List<? extends Animal>,即您可以将类型的值分配List<Cat>给类型 的变量/参数List<? extends Animal>。由于它不交换类型 ( Cat \xe2\x89\xa4 Animal),因此这是协方差。(另请参阅如何在 Java 泛型中使用逆变?

\n

引用相同的维基百科文章 \xe2\x80\x99s关于使用站点差异注释(通配符)的部分(如 Java 中):

\n
\n

通配符类型的上界是协变的(下界也是逆变的)。总的来说,给定一个像 的通配符类型C<? extends T>,可以通过三种方式形成子类型:通过专门化类C、指定更紧密的界限、或者用特定类型T替换通配符。?

\n
\n

(您可以在上面替换C<? extends T>为,它只是产生下限而不是上限)。C<? super T>T

\n