Java 流中的泛型

Java Generics in Stream

我知道你用 从集合中获取 个值时,扩展> 通配符。

假设有 Animal 超类以及 Dog 和 Cat 子类。基本上我想要一个包含狗和猫的列表。我发现我可以做到以下几点:

List<? extends Animal> animalList;
List<Dog> dogList = getDogs();
List<Cat> catList = getCats();

animalList = Stream.concat(dogList.stream(), catList.stream()).collect(Collectors.toList())

// Do things according to its type
for (Animal animal : animalList) {
    if (animal instance of Dog) {...}
    if (animal instance of Cat) {...}
}

以上代码编译通过。那么它是否违反了我正在 值写入 animalList 的规则?

Stream.concat(dogList.stream(), catList.stream()).collect(Collectors.toList())

这将创建一个 List<Animal>。至关重要的是,不是 List<? extends Animal>。试试看:

List<Animal> = ... all that ...

工作正常。

List<Animal> 并不意味着其中的所有内容都是按字面意思 new Animal() 制作的。您可以拥有仅包含 Cat 个实例的 List<Animal>。都是动物就好了

? extends 的 'point' 以及所有这些都是当您处理列表本身时,而不是其中的内容。具体原因如下:

List<Animal> x = new ArrayList<Cat>();
x.add(new Dog());
Cat z = x.get(0);

三次检查上面的代码,但它准确地解释了 ? extends(和 ? super)存在的原因。泛型必须 不变 ,否则会导致代码损坏。上面的代码一定不能编译,因为它没有意义。如所写,它确实无法编译 - 不允许第 1 行。您可以通过编写 List<? extends Animal> x = new ArrayList<Cat>() 来 'make it work' 编译正常,但现在 x.add(new Dog() 不会。

区别是这样的:

a List<Animal> 变量指向某个列表,该列表实际上是特定 <Animal> 的列表,而不是 Animal 的某些子类型或超类型。它可能是 LinkedList<Animal>ArrayList<Animal>,没关系,但不是 ArrayList<Cat>。知道了这一点,当你从它 'read' 中取出 Animal 对象时,当你写入它时,Animal 是好的。

另一方面,

a List<? extends Animal> 变量是 Animal 或 Animal 的某些子类型的列表。它可能是 LinkedList<Dog>。鉴于这一事实,当您阅读时,Animal 很好(Animal f = thatList.get(0) 可以编译),但您不能向其写入任何内容。它可能是狗的列表,但它也可能是猫的列表,因此绝对没有对象被保存(除了,平凡地,字面上的表达式 null,写成这样:thatList.add(null) 编译.当然没有用)。

您将 List<Animal> 表达式分配给 List<? extends Animal> 类型的变量,这很好。而且不需要; List<Animal> x = Stream.concat.... 也可以。