深入理解 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<String> stringList = new ArrayList<>();
// 检查 stringList 是否是 List 接口的实例
System.out.println("stringList instanceof List: " + (stringList instanceof List));
// 注意:泛型在运行时会被擦除,不能使用泛型类型进行 instanceof 检查
// 下面这行代码会编译错误
// System.out.println("stringList instanceof List<String>: " + (stringList instanceof List<String>));
}
}
输出结果:
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 )