java泛型 <?扩展 A> vs <A> vs <?超级A> [重复]

Posted

技术标签:

【中文标题】java泛型 <?扩展 A> vs <A> vs <?超级A> [重复]【英文标题】:java generics <? extends A> v.s <A> vs <? super A> [duplicate] 【发布时间】:2018-11-20 22:55:11 【问题描述】:

这可能是一个非常愚蠢的问题,但是我不明白为什么编译器会抱怨和编译。

我有两个非常简单的类:

class A 


class B extends A 

现在是代码:

//block1
List<A> list = new ArrayList<>();
list.add(new A()); //ok
list.add(new B()); //ok 

//block2
List<? extends A> extendList= new ArrayList<>();
extendList.add(new A()); //not ok, why?
extendList.add(new B()); //not ok, why?

//block3
List<? super A> superList = new ArrayList<>();
superList.add(new A()); //ok
superList.add(new B()); //ok. why?

block1 我知道它为什么起作用。

block2,我有&lt;? extends A&gt;,据我了解,该列表将接受类型为AA 的子类型的对象,例如B。为什么add() 两条线都失败了?有错误:

Error: no suitable method found for add(A)
method java.util.Collection.add(capture#1 of ? extends A) is not applicable
  (argument mismatch; A cannot be converted to capture#1 of ? extends A)
method java.util.List.add(capture#1 of ? extends A) is not applicable
  (argument mismatch; A cannot be converted to capture#1 of ? extends A)

block3,我有&lt;? super A&gt;,据我了解,该列表将接受类型为A 或超类型为A 的对象,B 是@987654334 的subType @,为什么add(new B())会编译?

我想我可能误解了superextends 关键字,我做了一些谷歌,但我的疑问仍然存在。

oracle通用教程的一句话:(https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html)

The term List<Number> is more restrictive than List<? extends Number>
because the former matches a list of type Number only, whereas the 
latter matches a list of type Number or any of its subclasses.

【问题讨论】:

我有一个猜测,但你可以试试List&lt;? extends A&gt; extendList= new ArrayList&lt;A&gt;(); 吗?我不认为&lt;&gt; 知道如何从 ,而 super A> 表示“A 的任何子类” 【参考方案1】:

List<? extends A> extendList= new ArrayList<>(); extendList.add(new A()); //not ok, why? extendList.add(new B()); //not ok, why?

假设您的AAnimal。现在你有一个List&lt;? extends Animal&gt;,所以你有一个动物的列表,它可以是DogCat,甚至是Animal,但你不知道是哪一个。你试图在其中插入一些东西(顺便说一句不可能),但你不能这样做,因为就像我说的那样,你不知道列表中有什么。它可能是List&lt;Cat&gt;,而您正尝试将Dog 插入其中。你甚至不能插入Animal - 因为Animal 可能是Dog,谁知道呢。

您可以从该列表中选择get,因为您知道您从该列表中选择的任何内容都可以分配给Animal,因此没有问题。请注意,在第 3 块中,您无法从列表中获取任何内容,但您可以插入 - 反之亦然。

您可以插入List&lt;? super Animal&gt;,因为您知道其中的任何内容都是动物或更高级别。所以你可以插入DogCatAnimal,因为它们都是动物。请注意,您无法从该列表中获取任何内容。这是Animal 的超类型列表,例如LivingBeing 列表(动物、人类等)。你会把它分配给什么? Human human = list.get(0) - 如果该特定对象不是人类而是动物怎么办? LivingBeing livingBeing = list.get(0) - 如果它不是活物列表,而是更高或完全不同的东西,但仍然是Animal 的超类型怎么办?

看看Effective Java 3rd edition 和Koltin in Action - 是的,Kotlin,它有一个稍微不同的方法可以帮助你更多地理解它。 Kotlin 语言将所有这些都纳入了清晰的规则中。

【讨论】:

【参考方案2】:

这里有一个场景来说明问题。考虑第三类:

class C extends A 


List<C> cList = new ArrayList<>();
List<? extends A> extendList = cList; //this is valid. Right? Yes

这样,失败的原因就清楚了。如果允许extendList.add(new A()),则以下内容也必须是合法的:

extendList.add(new B());

但随后我们将向列表(C)添加一个不兼容类型(B

原因是边界:&lt;? super A&gt; 保证与A 的任何子类型兼容。但是,&lt;? extends B&gt; 允许 A 的子类型可能彼此不兼容。

【讨论】:

【参考方案3】:

block2: “据我所知,列表将接受类型为 A 或 A 的子类型的对象,例如 B” - 不!考虑? 的可能值,例如它可能是class C extends A ,这意味着AB 都不匹配约束。您不能将AB 添加到泛型类型为C 的列表中。

block3:再次考虑? 的可能值:现在它可以是A 或其任何超类,所以AObject(或介于两者之间的任何值)。因为BA 的子类型,它当然也是A 的所有超类的子类型。每个接受AList 也将接受B

【讨论】:

以上是关于java泛型 <?扩展 A> vs <A> vs <?超级A> [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Java 泛型与 ArrayList <?扩展 A> 添加元素

java遗珠之泛型继承

Java 泛型啥时候需要 <?扩展 T> 而不是 <T> 并且切换有啥缺点吗?

java泛型-“扩展”关键字->不支持添加元素

Java 泛型 - Make Generic 扩展 2 个接口

Kotlin 泛型 VS Java 泛型