【Java面向对象】5-6 instanceof 关键字和引用类型转换

§5-6 instanceof 关键字和引用类型转换

在上一节,我们了解了 OOP 的第三个特征——多态。本节将围绕多态,了解 instanceof 关键字和引用类型转换。

5-6.1 instanceof 用法

用法instanceof 是一个二元操作符,用于测试左边的对象是否属于右边类的实例。返回一个布尔值,是则为 true,否则为 false

我们继续以上一节的类 ParentChild 为例。其中,在测试类中,我们有:

//实例一
Object object = new Child();
System.out.println(object instanceof Child);
System.out.println(object instanceof Parent);
System.out.println(object instanceof Object);
System.out.println(object instanceof String);

运行,得到结果:

true
true
true
false

其中,所涉及到的三个类的继承关系满足以下线性关系:Object -> Parent -> Child

这时,在原有的继承关系中,我们新建一个 Parent 的子类 Kid,将原有的继承关系从线性更改为树状结构。在测试类中测试一下代码:

//实例二
Parent parent = new Child();
System.out.println(parent instanceof Child);
System.out.println(parent instanceof Kid);
System.out.println(parent instanceof Parent);
System.out.println(parent instanceof Object);
System.out.println(parent instanceof String);

尝试编译,会发现最后一条语句编译不通过:

image

将最后一条语句注释掉后,再次运行,得到结果:

true
false
true
true

5-6.2 instanceof 特点与分析

综合上述两个例子来看,我们会发现:

  1. 当左边对象的引用变量类型与右边的类不存在继承关系时,编译不通过
  2. 编译时,编译器值判断数据类型是否符合,因此会比较左边的引用变量类型是否与右边的类具有继承关系;
  3. 实际运行时,JVM 会将两侧的对象所属类作比较,得出表达式的值;
  4. 同多态,instanceof 满足编译看左,运行看右的规则。

运用上述的发现分析上述示例:

编译时,根据多态的 ”编译看左“ 原则,编译器只会将 instanceof 左边引用变量的类型和右边的类类型做比较。若二者存在继承关系,则编译通过,但此时,编译器并不在乎该表达式的值。因此,示例一中引用变量 object 的类型是 Object ,而该类是所有除自己之外的类的父类,因此,编译通过。而实例二中,引用变量 parent 的类型是 Parent,而该类与 String 并不存在继承关系,因此,编译不通过,触发异常。

运行时,JVM 比较的是对象本身所属的类类型。若 instanceof 左边的引用变量所指对象的类类型(即对象的实际类型)属于右边的类的子类或自己,则返回 true,否则,左边对象实际类型是右边的类的父类或关系中属于同级关系,则返回 false

自 JDK 14 起,instanceof 关键字具有了一种新用法(语法糖),将判断与转换结合在一起:

obj instanceof Bean newObjRef;

当上述的 instanceof 语句的值为 true 时,会将 obj 转换为 Bean 类的对象,名为 newObjRef;否则则不转换,返回 false

5-6.3 引用类型转换

在基础章节中,我们介绍过基本数据类型的类型转换。这里稍作回顾:

  1. 低级数据类型无需强制转换,可自动转换为高级数据类型,且不会发生精度、信息丢失;
  2. 将高级数据类型转换为低级数据类型,则必须使用强制转换,这一过程可能造成精度丢失;

类似地,我们把强制类型转换从基本数据类型扩展到引用数据类型,上述原则仍然成立。

我们继续以上一节的继承关系类为例(ParentChild):

Parent child = new Child();

父类优先级比子类更高,是高级数据类型。因此,由低级转向高级,向上传递,自动进行。

但如果想要通过父类访问子类特有方法,若不执行强制类型转换,根据 ”编译看左“ 的原则,编译器检查时发现父类不存在所需方法便会报错。因此,父类若想访问子类方法,必须向下转型

子类一定是父类的一个实例(实例化子类时必须先实例化父类),但是父类不一定是子类的实例。子类向上转型为父类时,子类特有的方法将会被舍去;父类强制转换为子类时,将无法补全子类特有的内容。

在使用强制类型转换时,应当注意:

  1. 只允许父类的引用指向子类的对象;
  2. 子类转换成父类,向上传递,自动进行;
  3. 父类转换为子类,向下传递,强制转换;
  4. 方便方法调用,减少重复代码,实现简洁性;
  5. 强制转换有风险,使用时还需斟酌。
posted @ 2023-04-11 20:36  Zebt  阅读(71)  评论(0)    收藏  举报