您需要了解为什么这通常无法正常工作,以及为什么让编译器在这里抱怨是件好事。
假设我们有一个类ParkingLot implements Collection<Cars>
,并且因为Car extends Vehicle
,这将自动使ParkingLot
也实现Collection<Vehicle>
。然后我可以将我Submarine
的放入ParkingLot
.
不那么有趣,但更简单地说:苹果的集合不是水果的集合。一组水果可能包含香蕉,而一组苹果可能不包含。
有一种方法可以解决这个问题:使用通配符。苹果的集合是“特定水果亚型”的集合。通过忘记它是哪种水果,你会得到你想要的:你知道这是你得到的某种水果。同时,你也不能确定你可以随意放水果。
在java中,这是
Collection<? extends Fruit> collectionOfFruit = bagOfApples;
// Valid, as the return is of type "? extends Fruit"
Fruit something = collectionOfFruit.iterator().next();
// Not valid, as it could be the wrong kind of fruit:
collectionOfFruit.put(new Banana());
// To properly insert, insert into the bag of apples,
// Or use a collection of *arbitrary* fruit
让我再次强调区别:
Collection<Fruit> collection_of_arbitrary_fruit = ...;
collection_of_arbitrary_fruit.put(new Apple());
collection_of_arbitrary_fruit.put(new Banana());
必须能够储存任何水果、苹果和香蕉。
Collection<? extends Fruit> collection_of_one_unknown_kind_of_fruit = ...;
// NO SAFE WAY OF ADDING OBJECTS, as we don't know the type
// But if you want to just *get* Fruit, this is the way to go.
可以是一组苹果、一组香蕉、一组仅青苹果或一组任意水果。你不知道哪种水果,可能是混合的。但他们都是水果。
在只读情况下,我明确建议使用第二种方法,因为它允许专门的(“仅苹果袋”)和广泛的集合(“混合水果袋”)
理解这一点的关键是阅读Collection<A>
为不同类型 ACollection<? extends A>
的Collection ,而是A 的某些子类型的 Collection(但确切的类型可能会有所不同)。