关于Java协变性的思考
来源:互联网 发布:php麻将机器人ai算法 编辑:程序博客网 时间:2024/06/09 19:02
Java协变性
一、什么是协变性?
简而言之,如果A IS-A B,那么A[] IS-A B[]。
举例:现在有类型Person、Employee和Student。Employee 是一个(IS-A) Person,Student是一个(IS-A)Person。那么下面的语句可以通过编译:
Person[] arr = new Employee[5]; //能通过编译,因为协变性,数组是兼容的 arr[0] = new Student(); //能通过编译,因为Student IS-A Person
但是上面的代码在运行时却会出错。因为arr[0]实际上是引用一个Employee,可是Student IS-NOT-A Employee。这样就产生了混乱。这种错误正是由于Java数组的协变性而产生的。那么Java为什么不禁止数组协变呢?因为SE5之前还没有泛型,但很多代码迫切需要泛型来解决问题。
例如Arrays.equals()方法的底层实现调用的是Object.equals()方法,和数组中元素的具体类型无关,这充分利用了Java中任何类型都继承自Object类的特性,避免了为每个类型都重新定义Arrays.equals()方法。而在没有泛型的时代,要让Object[]能接受所有数组类型,最简单的办法就是让数组接受协变,把String[],Integer[]都定义成Object[]的派生类,然后多态就起作用了。
二、为什么数组设计成”协变“不会有大问题呢?
这是基于数组的一个独有特性:
数组记得它内部元素的具体类型,并且会在运行时做类型检查。
因为arr[0]记得它内部的元素类型是Employee,所以运行时给它插入一个Student类型会报错。
这个特性使得Java数组协变带来的影响不会酿成大错——错误最终还是会被检测出来,只不过是从编译时推迟到了运行时。
正是有这个特性,Java当初才敢于把数组设计成协变的。虽然向上转型以后,编译期类型检查放松了,但因为数组运行时对内部元素类型的严格检查,不匹配的类型还是插不进去的。这也是为什么容器Collection不能设计成协变的原因——Collection不做运行时类型检查。
Java容器因为不具有协变性,因而少了灵活性。因此,在Java5中,Java通过通配符和泛型对容器进行了弥补。
- 关于Java协变性的思考
- Java 协变性 逆变性
- java里的协变性与逆变性
- Java 协变性 逆变性 学习笔记
- java 协变性 逆变性 学习笔记
- C#的协变性和逆变性
- java 协变性和兼容性
- 数组的协变性与范型的不可变性
- Java中字符串的不可变性
- java之String对象的不可变性
- 以java为例理解协变性
- Java基本学习:数组--协变性
- 中庸之道:关于java的思考
- Java 关于对象的思考
- java的协变性之于数组及list的分析。
- 关于思考的思考
- 关于思考的思考
- 简易Java(06):图解Java字符串的不可变性
- JUnit 命令行运行
- 集合框架
- 利用python进行数据分析(五):数据规整化
- 一种跳来跳去的与迭代语法糖yield和迭代接口
- DER编码规则详解
- 关于Java协变性的思考
- IntelliJ IDEA 17 创建maven项目
- STM32串口发送数据第一个字节丢失问题
- 数据结构有序表的创建与输出
- Linux安装jdk
- 指针
- Strus2(十三)---输入验证
- JAVA多线程常见问题总结
- 当互联网的产品经理遇上物联网的产品经理,会是怎样的场景?