为什么我不能将 B 超类的对象放入 Container<?超级B>?

Why can't I put an object of superclass of B into Container<? super B>?

我有下面的代码。似乎我无法将 class Nonlife 的对象(它是 class Vehicle 的超 class 对象放入 [=13= 类型的容器中] ALTHOUGH通配符类型中有关键字“super”,只有classVehicleSUV的对象是子class of class 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());
    }
}

这是一个 Wildcard Capture 问题。

TL;DR - 当您在通用集合类型定义中使用通配符(使用 superextends)时,可以考虑从该集合中获取元素并适当地转换它 安全,而向集合中添加元素则不是,为了安全起见,实现了这个机制。

让我们检查一下 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> 的条件,但从整数值列表中取出一个项目并尝试将其放入列表中显然是不正确的Double 值。

另一个我喜欢的例子是Jon Skeet, and it looks like this

您可能还想阅读 this

关于 Collection<? super Vehicle>,您唯一确定的是它是载具的集合,或者载具超类型的集合。因此,您唯一确定可以放入此集合的是车辆。因此,您可以将 NonLifes 的集合传递给该方法,但您仍然只能将 Vehicles 或子类型放入该方法中的集合中。

总的来说:使用 super,你可以将提到的类型或子类型的值放入其中。使用扩展,您可以从集合中检索提到的类型,或将它们作为超类型检索。