Java不允许在<?扩展superType>是列表的已声明泛型类型。因为在这种情况下,列表被视为只读,以强制它只包含其动态类型的对象。
//1注释的行将返回编译错误。
我的问题是:
- 为什么行会被//2编译?它最终将多个子类型对象放入列表中
- 如果这里没有问题,那么为什么要在//1处抛出编译错误呢
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
class Scratch {
static class Animal {}
static class Dog extends Animal {}
static class Cat extends Animal {}
public static void main(String[] args) {
List<Cat> cats = new ArrayList<>();
List<Dog> dogs = new ArrayList<>();
//List<? extends Animal> animalsOfTwoTypes = new ArrayList<Dog>();
//animalsOfTwoTypes.add(new Dog()); //1
List<? extends Animal> animals = Stream.of(cats, dogs) //2
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
}
它最终将多个子类型对象放入列表中。
是的,但它们都是Animal
的亚型。您还没有指定列表中元素的类型;编译器所要做的就是检查列表的结果类型是否与变量类型兼容。
你本可以写:
List<Animal> animalsWithoutWildcard = Stream.of(cats, dogs) //2
.flatMap(Collection::stream)
.collect(Collectors.toList());
这也很好。然后
List<? extends Animal> animals = animalsWithoutWildcard;
也可以,因为Animal
的列表也可以用作从中获取Animal
实例的列表:animals
是Animal
实例的生产者,而animalsWithoutWildcard
既是Animal
实例的又是消费者。
重点不是List<? extends Animal>
变量引用的东西不能添加东西(除了null
(,而是不能通过该变量添加东西。因此:
System.out.println(animals.size()); // N
animalsWithoutWildcard.add(new Dog()); // fine
System.out.println(animals.size()); // N + 1
// but this is an error, even though it's the same list.
animals.add(new Dog());