instanceof关键字深入理解

2459

深入理解 instanceof 关键字

1. 基本概念回顾

instanceof 运算符用于判断一个对象是否是指定类或接口的实例,或者是否是该类的子类、该接口的实现类的实例。它返回一个布尔值,若对象是指定类型的实例则返回 true,否则返回 false。其基本语法为:

object instanceof Class/Interface

这里出现第一个注意点:

左侧操作数:必须是一个对象引用表达式,可以是一个变量、方法调用的返回值或者其他能产生对象引用的表达式。例如多态中的父类引用指向子类对象,其中左边的父类就是引用类型。右侧操作数:必须是一个类、接口的名称。

直接说instanceof返回true还是false的结论:

如果在此次实例过程中左侧的操作数(即引用类型)与右侧的操作数(实例对象)存在关系则返回true,反之则返回false。

具体是什么意思呢?

例如,父类Person和子类Student:

Person person = new Student();

在这个过程中是不是实例化了一个Student类,那么实例化子类的过程中必定先构造父类,即在这个过程中其实是先构造所有类的父类Object–>再构造Person–>再构造的Student。那么我就称在此次实例过程中Object、Person、Student类有关系,所以接下来的判断中只要左边的引用类型是这三个类其中的一种,右边的实例类型也是这三个的一种,都会返回true(即只要左右有关——这里的有关指继承、实现关系,就返回true)。

但是要注意:

因为Object类是所有类的父类,那么Object类其实也是String类的父类,按理说用instanceof也会返回true,但是我们一定要注意定语在这一次的实例过程中,我们在这一次的实例过程中只跟Object–>Person–>Student有关,所以涉及String的都会返回false。

易错点:

class Person {}

class Student extends Person {}

public class Main {

public static void main(String[] args) {

Student student = new Student();

Person person = student;

// 以下情况返回 true,这个就是讲的两边有关就true

System.out.println(student instanceof Student);

System.out.println(student instanceof Person);

System.out.println(student instanceof Object);

System.out.println(person instanceof Student);

System.out.println(person instanceof Person);

System.out.println(person instanceof Object);

// 错误示例,如果创建一个新的 Person 对象

Person anotherPerson = new Person();

// 这里返回 false,因为 anotherPerson 不是 Student 类型

System.out.println(anotherPerson instanceof Student);

}

}

解释第二个实例过程为什么会返回false:

这里为什么返回false呢,因为我这个实例化过程其实只是与Object–>Person有关,与Student无关,所以判断与Student有关的自然而然就返回false了。

2. 详细示例及解释

示例 1:类的继承关系中的 instanceof

// 定义一个父类

class Vehicle {

public void move() {

System.out.println("Vehicle is moving");

}

}

// 定义一个子类,继承自 Vehicle

class Car extends Vehicle {

public void honk() {

System.out.println("Car is honking");

}

}

public class InstanceofExample1 {

public static void main(String[] args) {

// 创建一个 Car 对象

Car car = new Car();

// 创建一个 Vehicle 引用指向 Car 对象

Vehicle vehicle = new Car();

// 检查 car 是否是 Car 类的实例

System.out.println("car instanceof Car: " + (car instanceof Car));

// 检查 car 是否是 Vehicle 类的实例

System.out.println("car instanceof Vehicle: " + (car instanceof Vehicle));

// 检查 vehicle 是否是 Car 类的实例

System.out.println("vehicle instanceof Car: " + (vehicle instanceof Car));

// 检查 vehicle 是否是 Vehicle 类的实例

System.out.println("vehicle instanceof Vehicle: " + (vehicle instanceof Vehicle));

}

}

输出结果:

car instanceof Car: true

car instanceof Vehicle: true

vehicle instanceof Car: true

vehicle instanceof Vehicle: true

解释:

car 是 Car 类的实例,由于 Car 继承自 Vehicle,所以 car 也是 Vehicle 类的实例。(即我说的实例化过程中会先构造父类,所以也与父类有关,即使左边和右边都没有涉及父类)vehicle 引用指向的实际对象是 Car 类的实例,因此 vehicle 既是 Car 类的实例,也是 Vehicle 类的实例。

示例 2:接口实现关系中的 instanceof(与继承关系类似的)

// 定义一个接口

interface Flyable {

void fly();

}

// 定义一个类实现 Flyable 接口

class Bird implements Flyable {

@Override

public void fly() {

System.out.println("Bird is flying");

}

}

public class InstanceofExample2 {

public static void main(String[] args) {

// 创建一个 Bird 对象

Bird bird = new Bird();

// 创建一个 Flyable 引用指向 Bird 对象

Flyable flyable = new Bird();

// 检查 bird 是否是 Bird 类的实例

System.out.println("bird instanceof Bird: " + (bird instanceof Bird));

// 检查 bird 是否是 Flyable 接口的实例

System.out.println("bird instanceof Flyable: " + (bird instanceof Flyable));

// 检查 flyable 是否是 Bird 类的实例

System.out.println("flyable instanceof Bird: " + (flyable instanceof Bird));

// 检查 flyable 是否是 Flyable 接口的实例

System.out.println("flyable instanceof Flyable: " + (flyable instanceof Flyable));

}

}

输出结果:

bird instanceof Bird: true

bird instanceof Flyable: true

flyable instanceof Bird: true

flyable instanceof Flyable: true

解释:

bird 是 Bird 类的实例,同时 Bird 类实现了 Flyable 接口,所以 bird 也是 Flyable 接口的实例。flyable 引用指向的实际对象是 Bird 类的实例,因此 flyable 既是 Bird 类的实例,也是 Flyable 接口的实例。

怎么和继承一样理解?你这样想:我实现一个接口,肯定得先知道这个接口,那是不是就先构造接口,那不就是接口–>实现接口的类,即接口与实现接口的类有关系,即使是Bird bird = new Bird(),左右两边都没有涉及接口类,但是由于我这个Bird类里面本来就是会实现接口中的方法,所以还是有关系(和上述示例1中的Car car = new Car()类似)。

示例 3:null 值与 instanceof

这个比较特殊,就是如果引用类型为null,那么不论如何instanceof都返回false。

public class InstanceofExample3 {

public static void main(String[] args) {

Object obj = null;

// 检查 null 对象是否是 Object 类的实例

System.out.println("obj instanceof Object: " + (obj instanceof Object));

}

}

输出结果:

obj instanceof Object: false

解释:null 表示没有引用任何对象,所以 null 不是任何类或接口的实例,instanceof 对 null 操作始终返回 false。

应用

示例1:使用 instanceof 进行类型转换前的检查

class Animal {

public void makeSound() {

System.out.println("Animal makes a sound");

}

}

class Cat extends Animal {

@Override

public void makeSound() {

System.out.println("Meow");

}

public void scratch() {

System.out.println("Cat is scratching");

}

}

public class InstanceofExample4 {

public static void main(String[] args) {

Animal animal = new Cat();

// 检查 animal 是否是 Cat 类的实例

if (animal instanceof Cat) {

// 进行向下转型

Cat cat = (Cat) animal;

cat.makeSound();

cat.scratch();

}

}

}

输出结果:

Meow

Cat is scratching

解释:

首先创建一个 Animal 引用指向 Cat 类的实例。使用 instanceof 检查 animal 是否是 Cat 类的实例,如果是,则进行向下转型,将 animal 转换为 Cat 类型,然后调用 Cat 类特有的方法 scratch()。

示例 2:结合泛型使用 instanceof

import java.util.ArrayList;

import java.util.List;

public class InstanceofExample5 {

public static void main(String[] args) {

List stringList = new ArrayList<>();

// 检查 stringList 是否是 List 接口的实例

System.out.println("stringList instanceof List: " + (stringList instanceof List));

// 注意:泛型在运行时会被擦除,不能使用泛型类型进行 instanceof 检查

// 下面这行代码会编译错误

// System.out.println("stringList instanceof List: " + (stringList instanceof List));

}

}

输出结果:

stringList instanceof List: true

解释:

stringList 是 ArrayList 类的实例,而 ArrayList 实现了 List 接口,所以 stringList 是 List 接口的实例。由于 Java 的泛型在运行时会被擦除,不能使用泛型类型进行 instanceof 检查,否则会导致编译错误。

3. Java 14 及以后的模式匹配 instanceof

在 Java 14 及以后的版本中,引入了模式匹配的 instanceof 语法,它可以在检查类型的同时进行类型转换,使代码更加简洁。

class Fruit {

public void taste() {

System.out.println("Fruit has a taste");

}

}

class Apple extends Fruit {

@Override

public void taste() {

System.out.println("Apple is sweet");

}

public void makeJuice() {

System.out.println("Making apple juice");

}

}

public class PatternMatchingInstanceOfExample {

public static void main(String[] args) {

Fruit fruit = new Apple();

// 使用模式匹配的 instanceof

if (fruit instanceof Apple apple) {

apple.taste();

apple.makeJuice();

}

}

}

输出结果:

Apple is sweet

Making apple juice

解释:

在 if 语句中,使用模式匹配的 instanceof 语法检查 fruit 是否是 Apple 类的实例**,如果是,则将其转换为 Apple 类型并赋值给 apple 变量,然后可以直接使用 apple 变量调用 Apple 类的方法。( 即实现了自动转换,其中Apple apple = (Apple)fruit )