Kotlin泛型:为何List<Int>、LinkedList<Int>无法add null但Queue<Int>可以?
Kotlin中
Queue<Int>可添加null但LinkedList<Int>/MutableList<Int>编译报错的原因 问题现象
对应测试代码如下:
import java.util.LinkedList import java.util.Queue fun main() { val list = mutableListOf<Int>() list.add(null) // 编译不通过,符合非空泛型的预期 val linkedList: LinkedList<Int> = LinkedList() linkedList.add(null) // 编译不通过 val queue: Queue<Int> = LinkedList() queue.add(null) // 无编译报错,运行可正常执行 }
根本原因
这个差异和泛型的协变、逆变规则没有关系,完全是Kotlin和Java互操作时的平台类型处理逻辑导致的:
kotlin.collections.MutableList是Kotlin原生定义的集合接口,它的add方法明确要求参数为非空的泛型类型E。当你声明泛型为非空的Int时,add方法只接受非空Int值,传null会直接被编译期空安全检查拦截。java.util.LinkedList是Java标准库提供的类,当你直接用LinkedList<Int>作为变量类型声明时,Kotlin会将你指定的非空泛型Int的约束应用到类的所有方法上,此时add方法的参数被识别为非空Int,传null同样会被编译拦截。- 当你把
LinkedList实例向上赋值给Queue<Int>类型的变量时,Kotlin读取的是Java原生java.util.Queue接口的方法签名。Java的Queue接口没有给泛型参数加任何@NonNull/@Nullable注解,Kotlin会将这里add方法的参数识别为平台类型Int!。平台类型不做编译期的空安全校验,你可以传非空值,也可以传null,编译器不会报错。
注意事项
- Java原生
LinkedList本身就支持存储null元素,因此queue.add(null)不仅编译能过,运行时也不会抛异常,null会被正常加入队列。 - 不要依赖这种隐式的编译检查来保证集合内无null:如果要求队列元素非空,要么使用Kotlin原生提供的非空集合实现,要么在添加元素时手动做null校验,避免Java互操作带来的空指针隐患。
内容的提问来源于stack exchange,提问作者Yantong_zhang
相关产品推荐
相关产品推荐

