开发者社区> 问答> 正文

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

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

展开
收起
微笑de向阳 2018-10-30 18:29:49 3918 0
2 条回答
写回答
取消 提交回答
  • 全栈工程师,从事了 12 年以 Java 语⾔为主的软件开发工作,热衷于整合框架与开发工具,关注 交互设计,喜欢写技术博客(http://codelife.me/),Linux拥趸,问题终结者。近期开始学习和关注 Elixir 函数语言,合作翻译了《Elixir 程序设计》。

    简单说不可以,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>
    2019-07-17 23:11:17
    赞同 展开评论 打赏
  • 追求性能极限的人

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

    2019-07-17 23:11:17
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载