为啥我不能将 B 的超类对象放入 Container<?超级B>? [复制]
Posted
技术标签:
【中文标题】为啥我不能将 B 的超类对象放入 Container<?超级B>? [复制]【英文标题】:Why can't I put an object of superclass of B into Container<? super B>? [duplicate]为什么我不能将 B 的超类对象放入 Container<?超级B>? [复制] 【发布时间】:2020-12-18 16:16:02 【问题描述】:我有下面的代码。似乎我无法将作为 Vehicle
类超类的 Nonlife
类的对象放入 Collection<? super Vehicle>
类型的容器中 尽管 通配符中有一个关键字“super”类型,并且只有类 Vehicle
和 SUV
的对象是类 Vehicle
的子类是可行的。有人能给我一些建议吗?
public class SUV extends Vehicle
public class Vehicle extends Nonlife implements Externalizable
public class Nonlife extends Thing
public class Thing implements Comparable<Thing>, Serializable
public class SupperWildcardTest20200830
public static void main(String[] args)
Collection<Thing> coll = new ArrayList<>();
appendVehicle2Collection(coll);
appendSuv2Collection(coll);
for (Thing el: coll)
System.out.println("" + el);
public static void appendVehicle2Collection(Collection<? super Vehicle> coll)
coll.add(new Vehicle());
public static void appendSuv2Collection(Collection<? super Vehicle> coll)
coll.add(new SUV());
public static void appendNolife2Collection(Collection<? super Vehicle> coll)
/**
* incompatible types: Nonlife cannot be converted to CAP#1
* where CAP#1 is a fresh type-variable:
* CAP#1 extends Object super: Vehicle from capture of ? super Vehicle
*/
coll.add(new Nonlife());
【问题讨论】:
阅读此文可能有用:***.com/questions/4343202/… 【参考方案1】:关于Collection<? super Vehicle>
,你唯一确定的是它是一个Vehicles 的集合,或者是一个Vehicles 超类型的集合。因此,您唯一确定可以放入此系列的就是车辆。因此,您可以将一个非生命集合传递给该方法,但您仍然可以只将车辆或子类型放入该方法内的集合中。
一般来说:使用 super,您可以将提到的类型或子类型的值放入其中。使用扩展,您可以从集合中检索提到的类型,或将它们作为超类型检索。
【讨论】:
感谢您的回答。后来在我问了这个问题之后,我在 Core Java Edition 9 这本书中找到了一条语句:“直观地说,具有超类型边界的通配符允许您写入通用对象,而具有子类型边界的通配符允许您从通用对象中读取。” .目前,我只能像这些陈述(你的或书的)一般理解它。希望有一天我可以通过理解JVM和Java编译器来准确理解它。但我想这离现在还很远。【参考方案2】:这是一个Wildcard Capture 问题。
TL;DR - 当您在 Generic Collection 类型定义中使用通配符(无论是 super
或 extends
)时,从该集合中获取元素并适当地转换它可以被认为是安全,而将元素添加到集合中则不是,并且出于安全目的而实现此机制。
让我们检查一下 Oracle 文档中给出的 example,它说明了为什么需要这种安全性的原因(此示例使用 extends
,但同样的原则适用于 super
):
代码:
import java.util.List;
public class WildcardErrorBad
void swapFirst(List<? extends Number> l1, List<? extends Number> l2)
Number temp = l1.get(0);
l1.set(0, l2.get(0)); // expected a CAP#1 extends Number, got a CAP#2 extends Number;
l2.set(0, temp); // expected a CAP#1 extends Number, got a Number
不编译,因为它正在尝试一个不安全的操作,因为,如果你将调用这个方法如下:
List<Integer> li = Arrays.asList(1, 2, 3);
List<Double> ld = Arrays.asList(10.10, 20.20, 30.30);
swapFirst(li, ld);
虽然 List<Integer>
和 List<Double>
都满足 List<? extends Number>
的条件,但从 Integer 值列表中取出项目并尝试将其放入 Double 值列表中显然是不正确的。
我喜欢的另一个例子是Jon Skeet,它看起来像this。
您可能还想阅读this。
【讨论】:
肯定 super Vehicle> 读作任何属于 Vehicle 超类的类型? 我只是说第一句话似乎误导了我。 Car 是一种扩展 Vehicle 的类型。据我了解, Car 不匹配 。很高兴被证明是错误的 @mattfreake 我实际上完全改变了我的(最初是错误的)答案。 嗨@GiorgiTsiklauri,感谢您的回答。但我这个问题的意图不是关于 SomeClass> 和辅助方法的通配符捕获,而是关于为什么不能将超类的对象设置为 SomeClass super T> 虽然通配符类型中有关键字“super”。以上是关于为啥我不能将 B 的超类对象放入 Container<?超级B>? [复制]的主要内容,如果未能解决你的问题,请参考以下文章