[@倚贤][¥20] 泛型常用特点,List<String>能否转为List<Object>-问答-阿里云开发者社区-阿里云

开发者社区> 问答> 正文

[@倚贤][¥20] 泛型常用特点,List<String>能否转为List<Object>

微笑de向阳 2018-10-30 18:29:49 1857

泛型常用特点,List能否转为List

分享到
取消 提交回答
全部回答(2)
  • 倚贤
    2019-07-17 23:11:17

    简单说不可以,String 是 Object 的子类型,但是 List<String> 不是 List<Object> 的子类型,让我们为什么直观上会觉得 List<String>List<Object> 存在父子关系呢?那是因为 java 编译器认为 String[] 是 Object[] 的子类型。但是这个设计有些问题,看如下代码

    Object[] myArray = new String[]{"a", "b", "c"};
    myArray[1] = 1;
    System.out.println(myArray[1]);

    上面的代码能通过编译,但是会抛一个运行时异常,ArrayStoreException。虽然 Java 编译器认为 String[] 是 Object[] 的子类型,但是事实上并不是,它不符合里氏替换原则。所以在后来 JDK 引入范型的时候,就没有再让 List<String>List<Object> 的子类型。但为了兼容已有代码,数组已经改不过来了。

    里氏替换原则Liskov substitution principle

    如果对每一个类型为 T1 的对象 o1,都有类型为 T2 的对象 o2,使得以 T1 定义的所有程序 P 在所有的对象 o1 都换成 o2 时,程序P的行为没有变化,那么类型 T2 是类型 T1 的子类型。 

    通俗定义

    所有引用基类的地方必须能透明地使用其子类的对象。

    更通俗定义

    子类可以扩展父类的功能,但不能改变父类原有的功能。

    那问题又来了,如果 List<String>List<Object> 没有父子关系,那我们开发中碰到需要使用超类容器的场景该怎么办?
    举个例子 Apple 是 Fruit 的子类,Fruit 是 Food 的之类。有一个 Plate 范型类,把 Apple,Fruit 和 Food 作为参数类型。

    Plate<? extends Fruit> p=new Plate<Apple>(new Apple());
        
    //不能存入任何元素
    p.set(new Fruit());    //Error
    p.set(new Apple());    //Error
    
    //读取出来的东西只能存放在Fruit或它的基类里。
    Fruit newFruit1=p.get();
    Object newFruit2=p.get();
    Apple newFruit3=p.get();    //Error

    对于只读场景,Plate<? extends Frunt>Plate<Apple> 的超类

    Plate<? super Fruit> p=new Plate<Fruit>(new Fruit());
    
    //存入元素正常
    p.set(new Fruit());
    p.set(new Apple());
    
    //读取出来的东西只能存放在Object类里。
    Apple newFruit3=p.get();    //Error
    Fruit newFruit1=p.get();    //Error
    Object newFruit2=p.get();

    对于只写场景,Plate<? super Frunt>Plate< Fruit> 的超类

    这就引入了一个新的类型感念:变形 variance

    类型 说明 实例
    协变covariant 组合类型保持原类型的父子关系 Cat[] Animal[] 以及 List<Animal> List<? extends Animal>
    逆变contravariant 组合类型反转原类型的父子关系 List<Cat> List<? super Cat>
    不变invariant 组合类型忽略原类型的父子关系 List<Cat> List<Animal>
    0 0
  • oldmanpushcart
    2019-07-17 23:11:17

    Java中泛型是类型擦除的实现方式,所以List、List

    0 0
添加回答
+ 订阅

时时分享云计算技术内容,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。

推荐文章