V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
szuwl
V2EX  ›  程序员

怎样理解下面这段代码

  •  
  •   szuwl · 2021-03-25 15:22:43 +08:00 · 3629 次点击
    这是一个创建于 1099 天前的主题,其中的信息可能已经有所发展或是发生改变。
    List<? extends Number> arr = Arrays.asList(1,2,3.1f,4.1d);
    

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

    第 1 条附言  ·  2021-03-25 16:34:24 +08:00
    让我困惑的就是 java 不允许 List<? extends Number> arr 中添加元素,但是却允许使用元素初始化 arr 。
    ```java
    List<? extends Number> arr = new ArrayList<Number>(){{ add(1); }};
    ```
    36 条回复    2021-03-26 14:46:27 +08:00
    sbdx
        1
    sbdx  
       2021-03-25 15:40:30 +08:00   ❤️ 2
    编译器猜的
    Jooooooooo
        2
    Jooooooooo  
       2021-03-25 15:51:13 +08:00
    不都是 Number 吗?

    List 可以装 Number.
    faust24601
        3
    faust24601  
       2021-03-25 15:54:48 +08:00 via iPhone
    范型协变
    xx6412223
        4
    xx6412223  
       2021-03-25 15:59:15 +08:00
    泛型检查,泛型擦除
    xuanbg
        5
    xuanbg  
       2021-03-25 16:00:05 +08:00
    extends Number,就是当作 Number 类型处理啊
    CodeCodeStudy
        6
    CodeCodeStudy  
       2021-03-25 16:00:45 +08:00
    List 里面装的是 Number,1,2,3.1f,4.1d 这些都是 Number
    szuwl
        7
    szuwl  
    OP
       2021-03-25 16:08:11 +08:00
    @CodeCodeStudy @xuanbg @Jooooooooo 这个 `list` 既然装的都是 `Number` 那为什么不允许再插入一个 `Number` 进去, `list.add(Integer.valueOf(1))` 将无法通过编译
    Chengx
        8
    Chengx  
       2021-03-25 16:09:15 +08:00
    @szuwl Arrays.asList 不可修改
    Chengx
        9
    Chengx  
       2021-03-25 16:09:52 +08:00
    @Chengx
    Arrays.asList 返回长度固定的 List
    支持 set 修改元素值
    不支持 add, remove, clear
    hello2060
        10
    hello2060  
       2021-03-25 16:11:07 +08:00 via iPhone
    实际类型就是 Number 啊,所以这语句没问题。
    wunaidouzi
        11
    wunaidouzi  
       2021-03-25 16:16:44 +08:00
    返回的是 Arrays 的内部类 ArrayList, 所以不能 add,remove,clear
    szuwl
        12
    szuwl  
    OP
       2021-03-25 16:17:06 +08:00
    @Chengx 首先产生的是编译期错误 `Required type: capture of ? extends Number,Provided: Integer`,而非运行时错误,你说的是运行时错误,再另说。
    szuwl
        13
    szuwl  
    OP
       2021-03-25 16:18:51 +08:00
    @Chengx @wunaidouzi
    ```java
    List<Number> arr = Arrays.asList(1,2,3.1f,4.1d);
    arr.add(Integer.valueOf(1));
    ```
    不会有编译器错误,只是在运行时候才会出现 `UnsupportedOperationException` 异常
    xuanbg
        14
    xuanbg  
       2021-03-25 16:25:17 +08:00
    @szuwl 运行时不是 List<Number>,而是 Arrays.asList(1,2,3.1f,4.1d)。这个对象不允许增减操作。
    szuwl
        16
    szuwl  
    OP
       2021-03-25 16:30:12 +08:00
    @xuanbg 那我换个表达:
    ```java
    List<? extends Number> arr = new ArrayList<Number>(){{ add(1); }};
    arr.add(1); //Required type: capture of ? extends Number,Provided: int
    ```
    这个 ArrayList 可以增减吧,但是第二句依然无法通过编译。
    kuko126
        17
    kuko126  
       2021-03-25 16:32:57 +08:00
    List<? super Number> arr = Arrays.asList(1,2,3.1f,4.1d);
    arr.add(Integer.valueOf(1));
    不会编译错误
    ipwx
        18
    ipwx  
       2021-03-25 16:35:43 +08:00
    @szuwl int != Integer
    szuwl
        19
    szuwl  
    OP
       2021-03-25 16:35:58 +08:00
    @kuko126 问的是 extends 并非 super
    Jwyt
        20
    Jwyt  
       2021-03-25 16:36:46 +08:00
    misdake
        21
    misdake  
       2021-03-25 16:36:55 +08:00
    学一下“协变”
    xuanbg
        23
    xuanbg  
       2021-03-25 17:25:55 +08:00
    @szuwl 'add(capture<? extends java.lang.Number>)' in 'java.util.List' cannot be applied to '(int)'
    richardxxx
        24
    richardxxx  
       2021-03-25 18:22:34 +08:00 via Android
    extends 能取不能存
    super 能存不能取
    CodeCodeStudy
        25
    CodeCodeStudy  
       2021-03-25 19:07:53 +08:00
    改成 ArrayList<? super Number> arr 就可以了
    AoEiuV020
        26
    AoEiuV020  
       2021-03-25 19:20:30 +08:00
    List<? extends Number> arr = Arrays.asList(1,2,3.1f,4.1d);
    List<? extends Number> arr = new ArrayList(Arrays.asList(1,2,3.1f,4.1d));
    理解一下这两个的区别,
    AoEiuV020
        27
    AoEiuV020  
       2021-03-25 19:24:00 +08:00
    搞错,是 extends 和 super 的区别,看来我也不熟,
    uselessVisitor
        28
    uselessVisitor  
       2021-03-25 22:54:24 +08:00
    1 不是包装类的子类吧,默认是 int 类型
    @szuwl
    uselessVisitor
        29
    uselessVisitor  
       2021-03-25 22:56:50 +08:00
    @beichenhpy 我理解错了,应该是 super 。。
    uselessVisitor
        30
    uselessVisitor  
       2021-03-25 23:57:19 +08:00
    逆变不能 get 吗?
    List<? super Integer> listSuper = new ArrayList<Number>();
    listSuper.add(1);
    System.out.println(listSuper.get(0));
    我试了一下编译通过了,也没有错误啊。。
    Chengx
        31
    Chengx  
       2021-03-26 09:17:37 +08:00
    @richardxxx 点睛之笔
    geminius2333
        32
    geminius2333  
       2021-03-26 10:16:47 +08:00
    Array.asList 方法返回的是 Arrays 的内部类。你要 add 可以 new ArrayList(Arrays.asList(...));
    no1xsyzy
        33
    no1xsyzy  
       2021-03-26 10:26:32 +08:00
    @beichenhpy 你不能 Integer x = listSuper.get(0)
    println 允许的范围大得多罢了,super 仍然潜在蕴含了 extends Object
    Bronya
        34
    Bronya  
       2021-03-26 10:33:27 +08:00
    本人拙见:
    初始化的时候已经确定了值都是 Number,因此允许初始化。
    但是添加的时候,`List<? extend Number>`并不知道到引用的哪一个子类,规定上界之后`List<? extend Number> = List<Integer> 和 List<? extend Number> = List<Double>`都是成立的,如果可以添加的话会造成`List<Integer>中添加了 Double 类型`,类似这样的代码:

    ```
    List<Integer> intList = new ArrayList<>();
    List<? extends Number> numList = intList;
    numList.add(0.1);//如果允许添加
    Integer integer = intList.get(0);//会造成 intList 存储了 Double
    ```

    因此规定上界(协变?)的时候能取不能存。
    super 同理。
    acr0ss
        35
    acr0ss  
       2021-03-26 14:24:43 +08:00
    List<? extends/ super T> 这个也曾困扰我,目前我的理解是。

    1. List<? extends/ super T> 而不是 List<T>,目的就是限定只能 add/get
    2. ? extends T 这种形式,因为父类无法强转为子类,但子类可以强转为父类;在只有明确上界 T 的 i 情况下,无法 add,只能 get 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2998 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 14:51 · PVG 22:51 · LAX 07:51 · JFK 10:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.