Java下界通配符疑问:List<? super Integer>含Double却无法添加Double?
搞懂Java泛型下界通配符:为啥你的列表能存Double却不能再加?
嘿,这个问题其实戳中了Java泛型里**下界通配符(? super T)**的核心规则,咱们一步步拆解:
1. 为啥List<? super Integer>里会有Double值?
先捋一遍你的代码逻辑:
List<? super Number> list1 = new ArrayList<>(); list1.add(10); // Integer是Number的子类,合法 list1.add(10.10); // Double也是Number的子类,合法 list1.add(20.20d);// 同上 List<? super Integer> list = list1; // 赋值合法
这里的关键有两点:
? super T的含义:List<? super Number>表示这个列表的实际类型是Number或它的父类(比如List<Number>、List<Object>),所以它允许添加Number及其所有子类(Integer、Double都满足)。- 泛型的编译检查 vs 运行时擦除:当你把
list1赋值给list时,这是完全合法的——因为Number是Integer的父类,能存Number的列表,肯定能存Integer的父类。但泛型信息在运行时会被擦除,JVM只知道这是个ArrayList,里面的元素早就被加进去了,后续的list变量类型只是限制新操作,不会影响已经存在的元素。所以打印时能看到Double,是因为这些元素是在列表的原始类型允许的范围内添加的。
2. 为啥list.add(30.30)编译不过?
这就是下界通配符的核心限制了:List<? super Integer>只能添加Integer或它的子类对象。
编译器不知道list指向的实际列表到底是什么类型——它可能是List<Integer>、List<Number>,甚至是List<Object>。如果允许你添加Double:
- 要是实际是
List<Integer>,那直接就类型错误了; - 就算实际是
List<Number>,编译器也不能赌这个情况,它必须保证所有可能的实际类型都能安全执行。
所以编译器只放行“肯定能放进任何? super Integer列表”的元素——也就是Integer及其子类(比如你自定义的MyInteger extends Integer)。Double不是Integer的子类,自然过不了编译这一关。
一句话总结:
- 已有的Double是在列表原始类型(
List<? super Number>)的规则下合法添加的,后续变量类型管不了已经存在的元素; - 新添加元素时,编译器会严格按照
List<? super Integer>的安全规则检查,只允许Integer家族的成员,避免类型风险。
内容的提问来源于stack exchange,提问作者Adithya
相关产品推荐
相关产品推荐

