Java泛型:List<? super List<? super Integer>>与List<? extends List<? super Integer>>的用法及编译疑问咨询
? super与? extends的困惑解析 先看你给出的代码片段:
List<Double> doubleList = null; List<Integer> integerList = null; List<Number> numberList = null; //expression:1 List<? super List<? super Integer>> superDoubleList = Arrays.asList(doubleList, integerList,numberList); //expression:2 //此处加入doubleList会触发编译错误 List<? extends List<? super Integer>> extendsDoubleList = Arrays.asList(integerList,numberList);//doubleList
针对你的两个困惑,咱们逐个拆解:
问题1:为什么表达式1能编译通过?
你一开始的理解有点偏差,咱们得从嵌套泛型的层级和逆变规则入手:
首先,List<? super List<? super Integer>>的含义是:这是一个列表,它的元素可以是任何属于List<? super Integer>超类型的类型实例。
那List<? super Integer>的超类型有哪些?所有能容纳List<? super Integer>的父类型,比如List<?>、Collection<?>等等。而Arrays.asList(doubleList, integerList, numberList)会自动推断出一个最通用的元素类型——List<?>,因为List<Double>、List<Integer>、List<Number>都可以赋值给List<?>。
接下来看赋值逻辑:List<List<?>>(Arrays.asList的返回类型)能不能赋值给List<? super List<? super Integer>>?
根据泛型的逆变规则:如果类型A是类型B的超类型,那么List<B>是List<? super A>的子类型。这里List<?>是List<? super Integer>的超类型,所以List<List<?>>是List<? super List<? super Integer>>的子类型——自然可以顺利赋值,所以编译不会报错。
简单说:所有传入的列表都能被向上转型为List<?>,而List<?>是List<? super Integer>的超类型,符合? super的约束。
问题2:为什么加入doubleList会触发编译错误?
同样先明确List<? extends List<? super Integer>>的含义:这是一个列表,它的元素必须是**List<? super Integer>的子类型实例**。
那哪些类型属于List<? super Integer>的子类型?根据逆变规则,只有当列表的元素类型是Integer的超类型时,这个列表才是List<? super Integer>的子类型——比如List<Integer>(Integer是自身的超类型)、List<Number>、List<Object>。
而List<Double>呢?Double和Integer是同级的Number子类,互相没有继承关系,所以List<Double>和List<? super Integer>之间不存在任何子类型/超类型关系。当你把doubleList加入Arrays.asList时,编译器找不到一个共同的类型,能同时容纳List<Double>、List<Integer>、List<Number>且符合? extends List<? super Integer>的约束,自然就会抛出编译错误。
总结一下:
List<Integer>/List<Number>能匹配List<? super Integer>的子类型要求,所以可以放入表达式2的列表List<Double>和List<? super Integer>完全不兼容,所以无法加入
内容的提问来源于stack exchange,提问作者theutonium.18

