This could be a very stupid question, however I don't understand why the compiler complains and compiles.
I have two very simple classes:
class A {
}
class B extends A {
}
Now the codes:
//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?
The block1 I know why it worked.
The block2, I have <? extends A>
, as I understood, the list is gonna accept objects with type A
or subType of A
, for example B
. Why both add()
lines failed? with error:
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)
The block3, I have <? super A>
, as I understood, the list is gonna accept objects with type A
or superType of A
, B
is a subType of A
, why add(new B())
compiles?
I think I could have misunderstanding of the super
and extends
keywords, I did some google, however my doubt is still there.
A sentence from oracle generic tutorial: ( https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html)
refresh_token
答案 0 :(得分:4)
block2:“据我所知,该列表将接受A类型或A类型的对象,例如B” - 不!考虑?
的可能值,例如它可能是class C extends A { }
,这意味着A
和B
都不匹配约束。您无法将A
或B
添加到通用类型为C
的列表中。
第3块:再次考虑?
的可能值:现在它可以是A
或其任何超类,所以A
或Object
(或中间的任何事情)。由于B
是A
的子类型,因此它当然也是A
的所有超类的子类型。接受List
的每个A
也会接受B
。
答案 1 :(得分:1)
这是一个明确的方案。考虑第三类:
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());
但是我们会将不兼容的类型(B
)添加到列表中(C
)
原因是边界:<? super A>
保证与A
的任何子类型兼容。但是,<? extends B>
允许A
的子类型彼此不兼容。
答案 2 :(得分:0)
List<? extends A> extendList= new ArrayList<>();
extendList.add(new A()); //not ok, why?
extendList.add(new B()); //not ok, why?
想象一下,您的A
是Animal
。现在你有一个List<? extends Animal>
,所以你有一个动物的列表,它可以是Dog
,Cat
甚至Animal
的列表,但是你不知道是哪一个。你试图插入一些东西(顺便说一下),你不能这样做,因为就像我说的那样,你不知道列表中的内容。它可以是List<Cat>
,您尝试在其中插入Dog
。您甚至无法插入Animal
- 因为Animal
可能是Dog
,谁知道。
您可以从该列表中get
,因为您知道从该列表中选择的任何内容都可以分配给Animal
,因此没有任何问题。请注意,在块3中,您无法从列表中获取任何内容,但您可以插入 - 反之亦然。
您可以插入List<? super Animal>
,因为您知道其中有动物或更高版本。因此,您可以插入Dog
,Cat
或Animal
,因为它们都是动物。请注意,您无法从该列表中获取任何内容。这是一个超级类型Animal
的列表,例如LivingBeing
列表(动物,人类等)。你会把它分配给什么? Human human = list.get(0)
- 如果那个特定物体不是人类而是动物怎么办? LivingBeing livingBeing = list.get(0)
- 如果它不是livingBeings的列表,而是更高或更简单的东西,但仍然是Animal
的超类?
看看Effective Java 3rd edition和Koltin in Action - 是的,Kotlin,它有一个稍微不同的方法,可以帮助你更多地了解它。 Kotlin语言将所有这些都纳入了清洁规则。