java泛型<?

java generics <? extends A> v.s <A> vs <? super A>

本问题已经有最佳答案,请猛点这里访问。

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

我有两个非常简单的课程:

1
2
3
4
5
class A {
}

class B extends A {
}

现在代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//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?

布洛克一号我知道它为什么起作用。

块2,我有,据我所知,列表将接受A类型或A子类型的对象,例如B。为什么两条add()线路都出现故障?有错误:

1
2
3
4
5
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)

布洛克3,我有,据我所知,列表将接受A型或A超类型的对象,BA的一个子类型,为什么add(new B())编译?

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

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

1
2
3
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.


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

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


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

1
2
3
4
5
class C extends A {
}

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

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

1
extendList.add(new B());

但是接下来我们将添加一个不兼容的类型(B到(C的)列表中)

原因是边界:保证与A的任何子类型兼容。但是,允许A的子类型彼此不兼容。


埃多克斯1〔24〕

假设你的AAnimal。现在你有一个List,所以你有一个动物的列表,它可以是DogCat,甚至Animal,但是你不知道是哪一个。你试图在其中插入一些东西(顺便说一下,这是不可能的),但你做不到,因为就像我说的,你不知道清单上有什么。可能是List,您试图在其中插入Dog。你甚至不能插入Animal,因为Animal可能是Dog,谁知道呢。

你可以从那张单子上选一个(36),因为你知道从那张单子上选的任何东西都可以分配给一个(26),所以没有问题。注意,在块3中,你不能从列表中得到任何东西,但是你可以插入——相反。

你可以插入到List中,因为你知道里面有动物或更高的动物。所以你可以插入DogCatAnimal,因为它们都是动物。注意,你不能从那个列表中得到任何东西。它是一个Animal的超类型列表,例如LivingBeing的列表(动物、人类等)。你会把它分配给什么?Human human = list.get(0)—如果那个特定的物体不是人而是动物呢?LivingBeing livingBeing = list.get(0)—如果它不是一个生命的列表,而是比这个更高或完全不同的东西,但仍然是Animal的一个超类型呢?

看看有效的Java第三版和KOLTIN在行动-是的,Kotlin,它有一个稍微不同的方法,这可以帮助你了解它更多。Kotlin语言把所有这些都放在了干净的规则中。