使用泛型方法在java泛型中使用'extends'和'super'的问题

Dau*_*aud 8 java generics collections

有一种方法:

public static <T> void addandDisp(Collection<T> cs, T t)

以下列方式调用:

List<? extends Object> ls2 = new LinkedList<Number>();
addandDisp(ls2,new Object());
Run Code Online (Sandbox Code Playgroud)

这给出了编译时错误.另一方面,如果我们只有一个参数,则调用成功.这是为什么 ?

此外,这是成功的:

List<? super String> ls1 = new LinkedList<String>();
addandDisp(ls1,new String());
Run Code Online (Sandbox Code Playgroud)

虽然这不是:

List<? super String> ls1 = new LinkedList<Object>();
addandDisp(ls1,new Object());
Run Code Online (Sandbox Code Playgroud)

底层逻辑是什么?

Kon*_*kov 11

我认为这addandDisp意味着添加和显示.

当你有一个集合,定义为:

List<? extends Object> ls2 = new LinkedList<Number>();
Run Code Online (Sandbox Code Playgroud)

这意味着,编译器将让你的总汇分配到所有可能的未知亚型Object.由于您具有该操作add,因此编译器拒绝为您提供绿灯,因为它不知道所提供的对象的类型是否满足对象的未知子类型的限制.这称为协方差.


类似的,当你有这样的定义:

List<? super String> ls1 = new LinkedList<String>();
Run Code Online (Sandbox Code Playgroud)

编译器允许您ls1协助:

  • LinkedList<String>(); //you can add Strings to the list
  • LinkedList<Object>(); //you can add Strings and Objects to the list

在这种情况下,编译器将完全意识到,如果你想传递对象满足条件是通用类型的集合的子类型.这称为逆变.

更多信息:


Sot*_*lis 1

另一方面,如果我们只有一个参数,那么调用就会成功。这是为什么 ?

您的方法有一个类型参数。当您调用方法时,您可以显式提供类型参数,也可以隐式推断类型参数。

当你像这样调用它时

addandDisp(ls2, new Object());
Run Code Online (Sandbox Code Playgroud)

编译器需要从两个方法参数中提取要绑定的类型T,因为两个方法参数都依赖于方法的类型参数T

这里的问题是? extends Object,并且Object不产生可以T安全绑定的单一类型。想象一下你有

public static <T> void addandDisp(Collection<T> cs, T t) {
    cs.add(t);
}
...
List<? extends Object> ls2 = new LinkedList<Number>();
addandDisp(ls2, new Object());
Run Code Online (Sandbox Code Playgroud)

add是不允许的,因为Object不应Number在预期使用 a 的地方使用 an。类型安全将会被破坏。

如果你有一个参数

public static <T> void addandDisp(Collection<T> cs) {
Run Code Online (Sandbox Code Playgroud)

然后编译器使用单个参数来推断类型参数。那么使用什么就没有歧义了。