技术解析

怎样理解下面这段代码
0
2021-06-08 15:10:55
idczone
List arr = Arrays.asList(1,2,3.1f,4.1d);

问题在于,list 变量并没有准确的类型,初始化的参数的类型也是不确定的,这样的不明确的代码为什么可以通过编译。


编译器猜的

不都是 Number 吗?
List 可以装 Number.

范型协变

泛型检查,泛型擦除

extends Number,就是当作 Number 类型处理啊

List 里面装的是 Number,1,2,3.1f,4.1d 这些都是 Number

这个 `list` 既然装的都是 `Number` 那为什么不允许再插入一个 `Number` 进去, `list.add(Integer.valueOf(1))` 将无法通过编译

Arrays.asList 不可修改


Arrays.asList 返回长度固定的 List
支持 set 修改元素值
不支持 add, remove, clear

实际类型就是 Number 啊,所以这语句没问题。

返回的是 Arrays 的内部类 ArrayList, 所以不能 add,remove,clear

首先产生的是编译期错误 `Required type: capture of ? extends Number,Provided: Integer`,而非运行时错误,你说的是运行时错误,再另说。


```java
List arr = Arrays.asList(1,2,3.1f,4.1d);
arr.add(Integer.valueOf(1));
```
不会有编译器错误,只是在运行时候才会出现 `UnsupportedOperationException` 异常

运行时不是 List,而是 Arrays.asList(1,2,3.1f,4.1d)。这个对象不允许增减操作。

允许修改的话类型不安全 你可以参见我这个 ts 的例子。父子类所构成的数组并不是父子关系 https://www.typescriptlang.org/zh/play?#code/MYGwhgzhAECC0G8BQ1XTNAvNAjEgvkqJDAELQCmAHgC4UB2AJjPMmtAEZbQBMBR4KNADClWg2ZxEKNMG59CRAPb0INTgC5opANoBdbvuWr1YLbH3cuAemvRAFzaB4Q0Cb8YBnE9NEAhboDztQKJpgHgVAejNtIyQwHQAGA2x6CgB3EQAKAEokJA5IvQA6Gzs3QA1tQAp1QDvUwAyMzkzoP2DRQEKbQEhzTiQgA

那我换个表达:
```java
List arr = new ArrayList(){{ add(1); }};
arr.add(1); //Required type: capture of ? extends Number,Provided: int
```
这个 ArrayList 可以增减吧,但是第二句依然无法通过编译。

List arr = Arrays.asList(1,2,3.1f,4.1d);
arr.add(Integer.valueOf(1));
不会编译错误

int != Integer

问的是 extends 并非 super

https://blog.csdn.net/Marmara01/article/details/85234908

学一下“协变”

https://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html

'add(capture)' in 'java.util.List' cannot be applied to '(int)'

extends 能取不能存
super 能存不能取

改成 ArrayList arr 就可以了

List arr = Arrays.asList(1,2,3.1f,4.1d);
List arr = new ArrayList(Arrays.asList(1,2,3.1f,4.1d));
理解一下这两个的区别,

搞错,是 extends 和 super 的区别,看来我也不熟,

1 不是包装类的子类吧,默认是 int 类型
@szuwl

我理解错了,应该是 super 。。

逆变不能 get 吗?
List listSuper = new ArrayList();
listSuper.add(1);
System.out.println(listSuper.get(0));
我试了一下编译通过了,也没有错误啊。。

点睛之笔

Array.asList 方法返回的是 Arrays 的内部类。你要 add 可以 new ArrayList(Arrays.asList(...));

你不能 Integer x = listSuper.get(0)
println 允许的范围大得多罢了,super 仍然潜在蕴含了 extends Object

本人拙见:
初始化的时候已经确定了值都是 Number,因此允许初始化。
但是添加的时候,`List`并不知道到引用的哪一个子类,规定上界之后`List = List 和 List = List`都是成立的,如果可以添加的话会造成`List中添加了 Double 类型`,类似这样的代码:
```
List intList = new ArrayList<>();
List numList = intList;
numList.add(0.1);//如果允许添加
Integer integer = intList.get(0);//会造成 intList 存储了 Double
```
因此规定上界(协变?)的时候能取不能存。
super 同理。

List 这个也曾困扰我,目前我的理解是。
1. List 而不是 List,目的就是限定只能 add/get
2. ? extends T 这种形式,因为父类无法强转为子类,但子类可以强转为父类;在只有明确上界 T 的 i 情况下,无法 add,只能 get 。

[PECS]( https://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super)

数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服