当前位置: 首页 > 知识库问答 >
问题:

为什么我不能把B超类的对象放入容器?[重复]

居焱
2023-03-14

我有下面的代码。似乎我不能将类Nonlife的超类对象放入类型为集合的容器中

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());
    }
}

共有2个答案

方飞翼
2023-03-14

这是一个通配符捕获问题。

TL; DR-当您在通用集合类型定义中使用通配符(无论是带有超级还是扩展)时,从该集合中获取元素并适当地转换它可以被认为是安全的,而将元素添加到集合中则不是,这个机制是为了安全目的而实施的。

让我们检查一下Oracle文档中给出的示例,它演示了为什么需要这种安全性的原因(该示例使用了扩展的但是同样的原则适用于超级代码):

代码:

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);

列表

我喜欢的另一个例子是乔恩·斯基特给出的,它看起来像这样。

你可能也想看看这个。

姬实
2023-03-14

关于收藏,你唯一能确定的是

一般情况下:使用super,可以将所述类型的值或子类型放入其中。使用extends,您可以从集合中检索提到的类型,或者将它们作为超类型检索。

 类似资料:
  • 我正试图从图中的窗体向表插入子层,但为什么不能使用where呢?

  • 我是css的新手,我正在尝试css注入,我在浏览器上更改主页的属性。 我有一个元素b,它有一个祖先a(不是直接的,中间有几个步骤)。 我读过很多次,通过在类之间使用空格,例如,您可以选择属于a类对象的后代的所有b类对象。 因此,注入会按预期将我的对象的颜色更改为白色。但是只使用不是,这一点我不理解,因为它应该影响b类的所有对象,不管它们的祖先是什么?

  • 我知道在原始数据类型的情况下自动类型提升的概念。但在参考数据类型的情况下,我有下面的代码可以完美地工作。 这给出了输出Array。 但是如果代替Object o,如果我们有任何其他类,那么这将显示编译时错误该方法对于Test4类型是模糊的 下面的代码给出编译时错误 正如我所知,每个引用数据类型(类、接口和数组)的默认值都是null。 那么为什么上面的代码在对象o的情况下工作呢。 提前谢谢

  • 我有自己的目录结构: 在我的Dockerfile中,我将复制到目录,但不幸的是,它没有被复制: 错误:

  • 如果我在锚元素中放置div元素,它会使我的超文本标记语言无效。 不在内联元素中放置块级元素的原因是什么?

  • 问题内容: 我正在向我的朋友解释OOP。我无法回答这个问题。(我有多可耻? 我只是想逃避,因为OOP描绘了现实世界。在现实世界中,父母可以容纳孩子,但孩子不能容纳父母。OOP也是如此。我知道它很愚蠢。:P 为什么此陈述无效? 因为aChild的成员是aParent成员的超集。那为什么孩子不能容纳父母。 问题答案: 正是因为aChild是aParent功能的超集。你可以写: 因为每只狐狸都是动物。但