为何两个List<? extends Number>变量赋值无编译错误?
为什么该Java方法不会触发编译错误
核心原因可以拆成两点讲:
- 第一,Java编译器校验引用赋值合法性的规则非常简单:只检查右侧表达式的静态类型是否和左侧变量的声明类型兼容,不会深入推演通配符背后实际绑定的具体泛型参数,也不会预判后续代码的操作。
- 第二,方法里
l1和l2的声明类型完全相同,都是List<? extends Number>,同类型引用互相赋值是最基础的合法操作,编译器没有理由拦截。
先明确List<? extends Number>的准确语义:它代表「一个元素类型为Number或Number子类的列表,具体是哪个子类未知」。这个类型本身就不要求所有同声明类型的引用必须指向同一个具体泛型参数的列表——它本来就是用来兼容所有Number子类型的List的。
这里要纠正一个常见误区:这段代码里的赋值操作本身不会产生任何运行时错误。
很多人误以为如果l1原本指向List<Integer>、l2指向List<Double>,赋值后会出现类型问题,实际上Java泛型的访问规则已经从编译层面彻底堵死了风险:
- 对于
? extends Number修饰的列表,除了null之外你没法添加任何元素,所有非null的add操作都会被编译器直接拦下,根本不可能把类型不匹配的元素塞进列表。 - 从这个列表里读取元素时,编译器只会把返回值当成Number类型处理,不管列表实际存的是Integer、Double还是其他Number子类,读取操作永远是类型安全的。
- 泛型在运行时是类型擦除的,所有List引用在字节码层面都是裸List类型,赋值操作只是传递内存地址,不存在类型转换的开销,也不会抛类型异常。
编译器根本不需要关心两个通配符背后实际绑定的类型是否一致,因为类型系统的约束已经保证:只要你不通过原生类型、反射等方式绕开泛型检查,这个赋值无论如何都不会引发运行时类型错误。
内容的提问来源于stack exchange,提问作者jacob12
相关产品推荐
相关产品推荐

