不是。List<Cat> 不是 List<Animal> 的子类型——Java 的泛型默认是不变的(invariant)。如果允许这种赋值,就能往 List<Cat> 里放入 Dog,破坏类型安全,所以编译器直接禁止。

协变与逆变的概念:协变(covariant)指子类型关系随容器保留——Java 数组是协变的,Cat[]Animal[] 的子类型,代价是运行期 ArrayStoreException 检查;逆变(contravariant)则方向相反。泛型中通过通配符实现受限的协变/逆变:List<? extends Animal> 是协变,可安全读出 Animal,但不能写入(null 除外);List<? super Cat> 是逆变,可写入 Cat 及其子类,读出只能按 Object 处理。

记忆口诀 PECS:Producer Extends, Consumer Super——只读取用 extends,只写入用 super。这正是 Collections.copy(List<? super T> dest, List<? extends T> src) 的设计。

List<? extends Animal> a = new ArrayList<Cat>(); // OK,可读
// a.add(new Cat()); // 编译错误
List<? super Cat> b = new ArrayList<Animal>();
b.add(new Cat()); // OK,可写

追问方向:为什么数组设计成协变?函数式接口中协变逆变的体现(返回值协变、参数逆变)?

(约 360 字)