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

为什么 arraylist<父类> arlst= new arraylist<子类>();不行呢

  •  
  •   misakawaque · 2021-01-04 18:51:01 +08:00 · 3439 次点击
    这是一个创建于 1417 天前的主题,其中的信息可能已经有所发展或是发生改变。
    为什么不能这样转换呢?
    19 条回复    2021-01-05 14:43:04 +08:00
    johnkiller
        1
    johnkiller  
       2021-01-04 18:54:55 +08:00
    ArrayList<? extends FatherClass> arlst = new ArrayList<ChildClass>();
    geelaw
        2
    geelaw  
       2021-01-04 18:57:45 +08:00 via iPhone
    因为范型参数 T 既要传入又要传出,因此是不变的。

    一个装橘子的列表有两个性质:取出来的东西都是橘子;是橘子的都能放进去。
    一个装水果的列表也有类似的两个性质。

    如果一个装橘子的列表 L is-a 装水果的列表,则任何是水果的东西都能装进 L,然而 L 不可以装苹果而苹果是水果。
    lululau
        3
    lululau  
       2021-01-04 19:02:11 +08:00 via iPhone
    哪个 Java Generics 的教程不讲这么基本的问题?
    Takamine
        4
    Takamine  
       2021-01-04 19:18:32 +08:00 via Android
    PECS 。
    hantsy
        5
    hantsy  
       2021-01-04 19:33:38 +08:00   ❤️ 4
    Child 是 Parent 的子类, 可以写 Parent p = new Child()

    但是 List<Child> 不是 List<Parent>子类,注意它们的 Type 是 List,而不是参数,就这么简单。
    maninfog
        6
    maninfog  
       2021-01-04 19:37:56 +08:00 via iPhone   ❤️ 1
    关键词 协变 逆变
    yuk1no
        7
    yuk1no  
       2021-01-04 19:41:35 +08:00 via iPhone
    因为这样写是 invariant 的
    misakawaque
        8
    misakawaque  
    OP
       2021-01-04 20:28:05 +08:00
    因为是看书自学的
    外国人语言还是蛮晦涩的,有什么推荐教程么
    lidlesseye11
        9
    lidlesseye11  
       2021-01-04 20:33:26 +08:00
    不如先说说如果能的话你想借此实现什么效果呢?
    声明了一个<父类>的 list,实际上指向的是个<子类>的 list ?

    或者说,假如 arraylist<父类> arlst= new arraylist<子类>() 没问题,那这个 list 的类型限制到底限制了个啥?
    接下来 arlst.add(父类)应该报错吗? arlst.add(子类)应该报错吗? arlst.add(另一个子类)应该报错吗?
    misakawaque
        10
    misakawaque  
    OP
       2021-01-04 20:41:09 +08:00
    @lidlesseye11
    简单来说就是自己看书产生的疑问
    就像一楼的 ArrayList<? extends FatherClass> arlst = new ArrayList<ChildClass>();是成立的
    而 arraylist<父类> arlst= new arraylist<子类>();不行
    就对他们的区别产生了疑问
    autogen
        11
    autogen  
       2021-01-04 21:00:42 +08:00
    可以这样:

    arraylist<父类> arr = new arraylist<>();
    arr.add(子类);
    leoleoasd
        12
    leoleoasd  
       2021-01-04 21:19:37 +08:00
    Java 中泛型是不变的,可有时需要实现逆变与协变,怎么办呢?这时,通配符?派上了用场:

    <? extends>实现了泛型的协变,比如:
    List<? extends Number> list = new ArrayList<Integer>();
    <? super>实现了泛型的逆变,比如:
    List<? super Number> list = new ArrayList<Object>();


    摘自 https://www.cnblogs.com/en-heng/p/5041124.html
    qwerthhusn
        13
    qwerthhusn  
       2021-01-04 21:39:03 +08:00
    来个? extends XXX 或者? super XXX 就行了
    Java 泛型语法复杂点的及其羞涩难懂,知道个大概就行了,后面用的时候慢慢就熟悉了
    mxalbert1996
        14
    mxalbert1996  
       2021-01-04 22:24:04 +08:00 via Android   ❤️ 3
    kx5d62Jn1J9MjoXP
        15
    kx5d62Jn1J9MjoXP  
       2021-01-04 23:23:37 +08:00
    List<鸡> chicks = new ArrayList<>();
    List<鸟> birds = chicks;
    birds.add(new 鸭());
    鸡 c = chicks.get(0);
    no1xsyzy
        16
    no1xsyzy  
       2021-01-05 00:57:12 +08:00
    范畴论( Category Theory )中的 协变 与 逆变
    吐槽下:面向对象的数学原理就是范畴论,但目前没有任何一门语言完全按照范畴论来设计面向对象架构,因为一个核心就是只能有 obj = obj.metaphor(field=new_value) ,不能有 obj.field=new_value,那就很不直观了。

    剩下的 #2 讲得挺清楚的。
    az467
        17
    az467  
       2021-01-05 01:07:33 +08:00
    1.因为 Java 类型构造器是不变的。
    2.ArrayList 是 mutable 的容器类,这么做符合里氏替换原则。
    3.就算你想让它协变逆变双变都不行,Java 不支持,换语言吧。
    Suddoo
        18
    Suddoo  
       2021-01-05 09:14:37 +08:00
    @hantsy 上次美团的面试官问了我这个问题,感觉回答得不够简练
    PoetAndPoem
        19
    PoetAndPoem  
       2021-01-05 14:43:04 +08:00
    @mxalbert1996 谢谢, 好久没看 effective java 了==
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1224 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 23:21 · PVG 07:21 · LAX 15:21 · JFK 18:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.