英文:
Why can't I put an object of superclass of B into Container<? super B>?
问题
下面是翻译好的代码部分:
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());
}
}
英文:
I have the code below. It seems that I can't put an object of class Nonlife
that is a superclass of class Vehicle
into a container of type Collection<? super Vehicle>
ALTHOUGH there is a keyword "super" in the wildcard type, and only objects of class Vehicle
and SUV
that is a subclass of class Vehicle
are feasible. Could someone give me some advice?
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());
}
}
答案1
得分: 2
你唯一确定的关于 Collection<? super Vehicle>
的是,它是一个 Vehicles 的集合,或者是 Vehicles 的超类型的集合。因此,你唯一确定可以放入该集合的是 Vehicles。所以你可以传递一个 NonLifes 的集合给这个方法,但在方法内部你仍然只能放入 Vehicles 或其子类型到集合中。
总体而言:使用 super,你可以放入所提到类型的值,或者其子类型。使用 extends,你可以从集合中检索所提到的类型,或者以超类型的形式检索它们。
英文:
The only thing you know for sure about Collection<? super Vehicle>
is that it is a collection of Vehicles, or a collection of a supertype of Vehicles. So the only thing you know for sure that you can put into this collection are Vehicles. So you are allowed to pass a Collection of NonLifes to the method, but you may still only put Vehicles or subtypes into the collection within the method.
In general: with super, you can put values of the mentioned type in it, or subtypes. With extends you can retrieve the mentioned type from the collection, or retrieve them as a supertype.
答案2
得分: 1
这是一个关于通配符捕获问题。
简而言之,当您在泛型集合类型定义中使用通配符(无论是带有super
还是extends
)时,从该集合获取元素并进行适当的转换被认为是安全的,而将元素添加到集合中则不安全。这个机制是为了安全起见而实现的。
让我们来看一下在Oracle文档中提供的示例,它演示了为什么需要这种安全性(此示例使用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)); // 预期得到 CAP#1 extends Number,实际得到 CAP#2 extends Number;
l2.set(0, temp); // 预期得到 CAP#1 extends Number,实际得到 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>
的条件,但显然从整数值列表中获取项目并尝试将其放入双精度值列表是不正确的。
我喜欢的另一个示例是由Jon Skeet提供的,它看起来像这样。
您还可能想阅读这篇文章。
英文:
This is a Wildcard Capture problem.
TL;DR - when you use a wildcard (be it with super
or extends
) in the Generic Collection type definition, getting element from that collection and casting it appropriately can be considered safe, while adding element into the collection is not, and this mechanism is implemented for the safety purpose.
Let's examine the example given in the Oracle Documentation, which demonstrates the reason of why this safety is needed (this example uses extends
but same principle applies for super
):
The code:
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
}
}
does not compile, as it is attempting an unsafe operation, because, if you will invoke this method as follows:
List<Integer> li = Arrays.asList(1, 2, 3);
List<Double> ld = Arrays.asList(10.10, 20.20, 30.30);
swapFirst(li, ld);
while List<Integer>
and List<Double>
both fulfill the criteria of List<? extends Number>
, it is clearly incorrect to take an item from a list of Integer values and attempt to place it into a list of Double values.
Another example I liked is given by Jon Skeet, and it looks like this.
You might also want to read this.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论