为何编译器允许将Pair<String,String>对象添加至Pair<String,Integer>列表?
为什么直接在add方法中创建错误泛型的Pair实例能通过编译?
我用Pair类存储体育场名称和容量信息,遇到了泛型检查的疑问:
- 第一个示例(符合预期):创建
List<Pair<String, Integer>>类型的列表后,显式声明Pair<String, String>变量并尝试添加,编译器报错,符合预期。 - 第二个示例(存在疑问):直接在
add方法内创建Pair<String, String>实例并添加,编译器未报错,程序可编译执行。
第一个示例(符合预期)
List<Pair<String, Integer>> stadiums = new ArrayList<>(); stadiums.add(new Pair("Bridgeforth Stadium", 25000)); stadiums.add(new Pair("Michigan Stadium", 109901)); Pair<String, String> stringPair = new Pair("Lane Stadium", "some str value"); stadiums.add(stringPair); // 编译错误:Required type:Pair<String,Integer> Provided:Pair<String,String>
第二个示例(存在疑问)
List<Pair<String, Integer>> stadiums = new ArrayList<>(); stadiums.add(new Pair("Bridgeforth Stadium", 25000)); stadiums.add(new Pair("Michigan Stadium", 109901)); stadiums.add(new Pair("Lane Stadium", "some str value")); // 无编译错误
原因解析
这是Java泛型的类型推断与原始类型特性共同作用的结果:
第一个示例的报错逻辑:
你显式声明了Pair<String, String>类型的变量stringPair,其泛型类型被明确固定。当传递给stadiums.add()时,编译器能直接对比变量类型与列表要求的Pair<String, Integer>,发现类型不匹配,因此抛出编译错误。第二个示例的无报错逻辑:
直接写new Pair("Lane Stadium", "some str value")时,未指定泛型参数,创建的是原始类型的Pair实例。Java的原始类型会绕过泛型检查(源于泛型擦除机制),编译器会将其视为兼容任意泛型参数的Pair,因此add方法不会触发编译错误。
⚠️ 注意:这种写法虽然能编译,但后续如果对列表中的该元素做类型相关操作(比如把getValue()的结果当作Integer处理),运行时会抛出ClassCastException。如果想让编译器在第二个示例中也报错,只需显式指定泛型参数:new Pair<String, String>("Lane Stadium", "some str value"),此时编译器就能检测到类型不匹配并报错。
内容的提问来源于stack exchange,提问作者Akramat
相关产品推荐
相关产品推荐

