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....
也可以。
我知道你用 从集合中获取 个值时,扩展> 通配符。
假设有 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....
也可以。