Dao*_*Wen 8 java generics java-8 bounded-wildcard
以下在JDK8中编译得很好,但是与JDK7 给出了不兼容的类型错误.
List<List<? extends Number>> xs = Arrays.asList(Arrays.asList(0));
Run Code Online (Sandbox Code Playgroud)
根据这个答案,List<List<? extends Number>>
没有超类型的关系List<List<Integer>>
.
在Java 8中改变了什么使得这个任务有效?我也有一个很难理解为什么它不会在Java 7的工作.
这两个语句使用JDK7编译时没有类型错误:
List<? extends Number> xs = Arrays.asList(0);
List<? extends List<? extends Number>> ys = Arrays.asList(Arrays.asList(0));
Run Code Online (Sandbox Code Playgroud)
对我来说,这两个都在JDK7中工作似乎非常不直观,但上面的原始示例却没有.所有这些当然都适用于JDK8.我想要真正理解这里发生了什么,我需要理解为什么这些例子在Java 7中是合法的,但原始的例子却不是.
基本上,在该调用上下文中,参数的类型0
在Arrays.asList(0)
可盒装到Integer
,然后加宽到Number
.当发生这种情况时,Arrays.asList(0)
返回类型为List<Number>
.通过相同的过程,List<Number>
可以在将List<? extends Number>
其用作外部参数之前进行转换Arrays.asList(..)
.
这相当于在Java 7中使用显式类型参数
List<List<? extends Number>> xs = Arrays.<List<? extends Number>>asList(Arrays.<Number>asList(0));
Run Code Online (Sandbox Code Playgroud)
在Java 7中,表达式的类型无论在何处使用都是相同的,无论是独立表达式还是在赋值表达式中使用.
Java 8引入了多表达式,其中表达式的类型可能受表达式的目标类型的影响.
例如,在以下赋值表达式中
List<Number> numbers = Arrays.asList(1);
Run Code Online (Sandbox Code Playgroud)
表达式Arrays.asList(1)
的类型是被调用方法的返回类型,它完全取决于泛型类型参数.在这种情况下,将推断该类型参数,Integer
因为该值1
可以Integer
通过装箱转换转换为(原语不能与泛型一起使用).所以表达式的类型是List<Integer>
.
在Java 7中,此赋值表达式无法编译,因为List<Integer>
无法分配List<Number>
.这可以通过在调用时提供显式类型参数来解决asList
List<Number> numbers = Arrays.<Number>asList(1);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,方法调用需要一个Number
参数作为其第一个参数,并且该值1
满足该参数.
在Java 8中,赋值表达式是poly表达式
如果满足以下所有条件,则方法调用表达式是poly表达式:
调用出现在赋值上下文或调用上下文中(第5.2节,第5.3节).
如果调用是合格的(即
MethodInvocation
除了第一个之外的任何形式),则调用TypeArguments
省略到标识符的左侧.由以下小节确定的要调用的方法是通用的(第8.4.4节),并且具有提及方法的类型参数中的至少一个的返回类型.
作为多义表达式,它可以受到它所分配的变量类型的影响.这就是发生的事情.泛型类型Number
影响调用中推断的类型参数Arrays.asList(1)
.
请注意它在以下示例中不起作用
List<Number> numbers = ...;
List<Integer> integers = ...; // integers is not a poly expression
numbers = integers; // nope
Run Code Online (Sandbox Code Playgroud)
所以它不是协方差,但我们在某些地方获得了一些好处.