为何Kotlin中可将子类类型List赋值给父类类型List?
为什么Java和Kotlin中泛型集合的赋值行为不一样?
1. Java的List<T>是「不变类型」
Java里的List<T>属于**不变(invariant)**泛型,简单说就是:哪怕FavouriteNote继承自Note,List<FavouriteNote>和List<Note>也完全是两个无关的类型,不能互相赋值。
- 背后原因是Java的
List是可读写的:如果允许把List<FavouriteNote>赋值给List<Note>,后续你可能会往notes里加一个普通Note对象,这就会导致原本只能存FavouriteNote的集合混入父类实例,运行时必然报错。编译器直接把这种风险掐死在编译阶段,所以你写的代码编译不通过。
2. Kotlin的List<T>是「协变类型」
Kotlin的List<T>接口天生是**协变(covariant)**的,它的定义是interface List<out E> : Collection<E>,这里的out关键字就是协变的标记。
- 协变的意思是:如果
FavouriteNote是Note的子类,那么List<FavouriteNote>自动成为List<Note>的子类,可以直接向上赋值。 - 为什么安全?因为Kotlin的
List是只读集合,它没有任何添加、修改元素的方法(这些操作全在MutableList里)。既然不能往里面加东西,就不存在混入非法类型的风险,完全保证类型安全。你示例里用的emptyList()返回的就是这种只读的协变集合,所以赋值能成功编译运行。
可以参考的学习内容
- Kotlin官方文档里的泛型章节,重点啃
out/in修饰符的作用,以及只读集合和可变集合的设计区别。 - Java官方文档中关于泛型不变性的说明,顺便理解
? extends T通配符的用法——这是Java里模拟只读协变的方式,比如List<? extends Note>就能接收List<FavouriteNote>。 - 对比两种语言泛型的设计思路,核心看它们是怎么在类型安全和易用性之间做平衡的。
内容的提问来源于stack exchange,提问作者bighugedev
相关产品推荐
相关产品推荐

