• java 泛型通配符 extends, super


    引自:http://sharewind.iteye.com/blog/1622164

    关键字说明

    • ? 通配符类型
    • <? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类
    • <? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型的超类型(父类型),直至Object

    extends 示例

    static class Food{}
    static class Fruit extends Food{}
    static class Apple extends Fruit{}
    static class RedApple extends Apple{}
    
    List<? extends Fruit> flist = new ArrayList<Apple>();
    // complie error:
    // flist.add(new Apple());
    // flist.add(new Fruit());
    // flist.add(new Object());
    flist.add(null); // only work for null 
    

    List<? extends Frut> 表示 “具有任何从Fruit继承类型的列表”,编译器无法确定List所持有的类型,所以无法安全的向其中添加对象。可以添加null,因为null 可以表示任何类型。所以List 的add 方法不能添加任何有意义的元素,但是可以接受现有的子类型List<Apple> 赋值。

    Fruit fruit = flist.get(0);
    Apple apple = (Apple)flist.get(0);
    

    由于,其中放置是从Fruit中继承的类型,所以可以安全地取出Fruit类型。

    flist.contains(new Fruit());
    flist.contains(new Apple());
    

    在使用Collection中的contains 方法时,接受Object 参数类型,可以不涉及任何通配符,编译器也允许这么调用。

    super 示例

    List<? super Fruit> flist = new ArrayList<Fruit>();
    flist.add(new Fruit());
    flist.add(new Apple());
    flist.add(new RedApple());
    
    // compile error:
    List<? super Fruit> flist = new ArrayList<Apple>();
    

    List<? super Fruit> 表示“具有任何Fruit超类型的列表”,列表的类型至少是一个 Fruit 类型,因此可以安全的向其中添加Fruit 及其子类型。由于List<? super Fruit>中的类型可能是任何Fruit 的超类型,无法赋值为Fruit的子类型Apple的List<Apple>.

    // compile error:
    Fruit item = flist.get(0);
    

    因为,List<? super Fruit>中的类型可能是任何Fruit 的超类型,所以编译器无法确定get返回的对象类型是Fruit,还是Fruit的父类Food 或 Object.

    小结

    extends 可用于的返回类型限定,不能用于参数类型限定。
    super 可用于参数类型限定,不能用于返回类型限定。
    >带有super超类型限定的通配符可以向泛型对易用写入,带有extends子类型限定的通配符可以向泛型对象读取。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    我的理解:

    泛化:给容器指定一种对象类型。在java中,子类可以赋值给父类容器,即向上赋值;而父类不可以赋值给子类容器,因为向下赋值需要增添新的属性等信息,这是无法完成的,即不能向下赋值。

    ===》List< ? super Fruit >

    • 表示List里存放的都是 Fruit 和 Fruit 的父类,但是在编译的时候并不清楚具体是哪个父类。
    • 直接向 List 赋值时,必须满足容器对象要求,从而必须赋值为 Fruit 或 Fruit 的父类。 因为编译时,完全符合要求,所以可以通过编译。在运行时,必须要确定 List 里放的是什么类型的对象。如果放 Fruit 子类,那么根本不知道要把 Fruit 子类泛化为哪种类型,从而最终运行时 List 存放的对象类型是不确定的。
    • 可以向 List add 任何 Fruit 和 Fruit 的子类。因为在编译时,可以确定 List 中至少是 Fruit,因此 Fruit 和 Fruit 子类 至少可以向上赋值给 Fruit,当然也可能赋值给 Fruit 父类,所以编译通过。 而在运行时,List 中存放的具体是 Fruit 的哪个父类已经确定了,add 的元素会直接转换为该父类,所以运行通过。
    • super 用于add元素,不用于 get 元素。因为编译时不确定是哪个父类,由于泛化限定,get只能赋值给 当前类型及其父类,那么只能赋值给 Object 对象了。所以 Object o = flist.get(0) 是可以的。

    ===》List< ? extends Fruit >

    • 表示 List 里存放的都是 Fruit 和 Fruit 的子类,但是在编译的时候并不清楚具体是哪个子类。
    • 直接向 List 赋值时,必须满足容器对象要求,从而必须赋值为 Fruit 或 Fruit 的子类。这里根本不可能赋值为父类,因为这违反了泛化的基本要求。
    • get元素可以赋值给 Fruit 和 Fruit 父类。因为 List 中存放的至多是 Fruit 类,所以向上赋值时, Fruit 和 Fruit 父类都是满足要求的。
    • extends 用于get元素,不用于add元素不可以向 List add 元素。因为编译时不确定 List 中存放的是哪个 Fruit 子类,如果 add 了某个子类,eg. Orange,而实际存储的是 Apple,那么根本类型就不匹配。所以只能add null。

     

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    使用 Sentry集中处理错误
    laravel实现多对多的分析
    windows下phpstorm的快捷键
    npm 升级
    squid----正向代理
    nginx----配置优化
    负载均衡----nginx
    负载均衡----HAproxy
    负载均衡----LVS
    mysql-8.0.12读写分离
  • 原文地址:https://www.cnblogs.com/hf-cherish/p/4387662.html
Copyright © 2020-2023  润新知