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

怎样理解下面这段代码

  •  
  •   szuwl · 308 天前 · 3054 次点击
    这是一个创建于 308 天前的主题,其中的信息可能已经有所发展或是发生改变。
    List<? extends Number> arr = Arrays.asList(1,2,3.1f,4.1d);
    

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

    第 1 条附言  ·  308 天前
    让我困惑的就是 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  
       308 天前   ❤️ 2
    编译器猜的
    Jooooooooo
        2
    Jooooooooo  
       308 天前
    不都是 Number 吗?

    List 可以装 Number.
    faust24601
        3
    faust24601  
       308 天前 via iPhone
    范型协变
    xx6412223
        4
    xx6412223  
       308 天前
    泛型检查,泛型擦除
    xuanbg
        5
    xuanbg  
       308 天前
    extends Number,就是当作 Number 类型处理啊
    CodeCodeStudy
        6
    CodeCodeStudy  
       308 天前
    List 里面装的是 Number,1,2,3.1f,4.1d 这些都是 Number
    szuwl
        7
    szuwl  
    OP
       308 天前
    @CodeCodeStudy @xuanbg @Jooooooooo 这个 `list` 既然装的都是 `Number` 那为什么不允许再插入一个 `Number` 进去, `list.add(Integer.valueOf(1))` 将无法通过编译
    Chengx
        8
    Chengx  
       308 天前
    @szuwl Arrays.asList 不可修改
    Chengx
        9
    Chengx  
       308 天前
    @Chengx
    Arrays.asList 返回长度固定的 List
    支持 set 修改元素值
    不支持 add, remove, clear
    hello2060
        10
    hello2060  
       308 天前 via iPhone
    实际类型就是 Number 啊,所以这语句没问题。
    wunaidouzi
        11
    wunaidouzi  
       308 天前
    返回的是 Arrays 的内部类 ArrayList, 所以不能 add,remove,clear
    szuwl
        12
    szuwl  
    OP
       308 天前
    @Chengx 首先产生的是编译期错误 `Required type: capture of ? extends Number,Provided: Integer`,而非运行时错误,你说的是运行时错误,再另说。
    szuwl
        13
    szuwl  
    OP
       308 天前
    @Chengx @wunaidouzi
    ```java
    List<Number> arr = Arrays.asList(1,2,3.1f,4.1d);
    arr.add(Integer.valueOf(1));
    ```
    不会有编译器错误,只是在运行时候才会出现 `UnsupportedOperationException` 异常
    xuanbg
        14
    xuanbg  
       308 天前
    @szuwl 运行时不是 List<Number>,而是 Arrays.asList(1,2,3.1f,4.1d)。这个对象不允许增减操作。
    szuwl
        16
    szuwl  
    OP
       308 天前
    @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  
       308 天前
    List<? super Number> arr = Arrays.asList(1,2,3.1f,4.1d);
    arr.add(Integer.valueOf(1));
    不会编译错误
    ipwx
        18
    ipwx  
       308 天前
    @szuwl int != Integer
    szuwl
        19
    szuwl  
    OP
       308 天前
    @kuko126 问的是 extends 并非 super
    misdake
        21
    misdake  
       308 天前
    学一下“协变”
    xuanbg
        23
    xuanbg  
       308 天前
    @szuwl 'add(capture<? extends java.lang.Number>)' in 'java.util.List' cannot be applied to '(int)'
    richardxxx
        24
    richardxxx  
       308 天前 via Android
    extends 能取不能存
    super 能存不能取
    CodeCodeStudy
        25
    CodeCodeStudy  
       308 天前
    改成 ArrayList<? super Number> arr 就可以了
    AoEiuV020
        26
    AoEiuV020  
       308 天前
    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  
       308 天前
    搞错,是 extends 和 super 的区别,看来我也不熟,
    beichenhpy
        28
    beichenhpy  
       307 天前
    1 不是包装类的子类吧,默认是 int 类型
    @szuwl
    beichenhpy
        29
    beichenhpy  
       307 天前
    @beichenhpy 我理解错了,应该是 super 。。
    beichenhpy
        30
    beichenhpy  
       307 天前
    逆变不能 get 吗?
    List<? super Integer> listSuper = new ArrayList<Number>();
    listSuper.add(1);
    System.out.println(listSuper.get(0));
    我试了一下编译通过了,也没有错误啊。。
    Chengx
        31
    Chengx  
       307 天前
    @richardxxx 点睛之笔
    geminius2333
        32
    geminius2333  
       307 天前
    Array.asList 方法返回的是 Arrays 的内部类。你要 add 可以 new ArrayList(Arrays.asList(...));
    no1xsyzy
        33
    no1xsyzy  
       307 天前
    @beichenhpy 你不能 Integer x = listSuper.get(0)
    println 允许的范围大得多罢了,super 仍然潜在蕴含了 extends Object
    Bronya
        34
    Bronya  
       307 天前
    本人拙见:
    初始化的时候已经确定了值都是 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  
       307 天前
    List<? extends/ super T> 这个也曾困扰我,目前我的理解是。

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