Java泛型赋值编译行为疑问:为何Float列表可赋值给List<? super Integer>且存在编译差异?
嘿,这个问题问得特别精准,戳中了Java泛型通配符里一个容易混淆的细节,咱们一步步拆解来看:
首先先再明确下? super Integer的核心含义:它代表任何能作为Integer父类型的类(包括Integer本身),也就是Integer、Number、Object这几类对应的列表,都能合法赋值给List<? super Integer>变量。
现在来分析你遇到的两种截然不同的编译结果:
第一种情况:为什么intList = floatList会编译报错?
你先定义了List<? super Float> floatList = List.of(1.1f,2.2f);,然后尝试把floatList赋值给intList(List<? super Integer>),编译器直接抛出类型不匹配的错误。
原因在于:? super Float对应的是Float的父类型集合——Float、Number、Object;而? super Integer对应的是Integer的父类型集合——Integer、Number、Object。这两个集合的交集是Number和Object,但编译器没办法确定floatList的实际具体类型到底是哪一个:
- 它可能是
List<Number>或者List<Object>,这两种确实符合List<? super Integer>的要求; - 但它也可能是
List<Float>,而Float和Integer是平级的Number子类,并不是Integer的父类型。如果允许把List<Float>赋值给List<? super Integer>,后续你可能会往intList里添加Integer元素,这会导致List<Float>中混入不兼容类型,彻底破坏类型安全。
编译器为了规避这种潜在风险,会直接阻止这个赋值操作——因为它没法100%保证floatList的具体类型一定在List<? super Integer>的合法范围内。
第二种情况:为什么intList = List.of(1.1f,2.2f)能正常编译?
这里的关键是编译器对List.of(...)的类型推断逻辑。当你直接把List.of(1.1f,2.2f)赋值给List<? super Integer>时,编译器会自动根据目标类型调整推断出的列表类型,比如推断为List<Number>或者List<Object>。
Float是Number的子类,List<Number>既可以容纳Float元素,同时Number又是Integer的父类型,完全符合List<? super Integer>的定义。编译器会帮你完成这个“适配性”的类型推断,让赋值操作合法。
简单总结:直接赋值List.of(...)时,编译器能根据目标类型灵活调整推断结果;而floatList已经被固定为List<? super Float>类型,编译器无法确定它的具体类型是否兼容,所以前者合法,后者报错。
备注:内容来源于stack exchange,提问作者Dmitriy Vasilyev

