Kotlin中逆变类型能否读取?无界通配符为何可读取?
问题解答
1. 逆变类型是否完全无法读取?
不是完全读不了,但不能直接通过逆变投影的集合调用读取方法:
- 像
List<in Class1>这种逆变投影,设计初衷是用来往里塞东西的(消费者):它能安全调用的是那些需要传入泛型类型参数的方法,比如add(),因为逆变保证它能接受Class1及其子类的对象。 - 但它不能直接调用
get()这种往外拿东西的方法(生产者)——编译器没法确定拿出来的到底是什么类型。比如你例子里的list实际是List<Class2>,但逆变投影只知道它能装Class1,拿出来的可能是Class2甚至更上层的类型,没法和Class1体系安全关联,所以直接调用get()会报错。 - 如果非要读,可以先把逆变投影转成
List<*>再读,比如:
fun main() { val list2: List<Class2> = listOf(Class2(), Class2()) val list: List<in Class1> = list2 val item: Any? = (list as List<*>)[0] }
2. 为何无界通配符*允许读取?它不该同时具备协变与逆变的限制吗?
这是对*的误解:
- Kotlin里的
List<*>其实是List<out Any?>的简化写法,属于协变投影,不是同时卡协变和逆变的限制。 - 协变投影的定位是用来往外拿东西的(生产者):所以它能安全调用
get()这类读取方法,返回值会被自动转成Any?——任何类型都能转成Any?,完全安全。 - 它的限制是不能随便往里塞东西(除了
null),因为编译器不知道这个集合的真实泛型类型,乱塞元素会破坏类型安全。 - 简单说,
List<*>是“能读不能写(除了null)”,和你以为的“既不能读也不能写”完全不是一回事。
内容的提问来源于stack exchange,提问作者excitedGoose
相关产品推荐
相关产品推荐

