CodeGym /课程 /JAVA 25 SELF /instanceof 的模式匹配

instanceof 的模式匹配

JAVA 25 SELF
第 65 级 , 课程 1
可用

1. 经典 instanceof 的问题

先来点小小的怀旧。在 Java 16 之前,当你需要先检查对象类型再按该类型使用它时,不得不写出冗长的模板:先用 instanceof 判断,再显式强转:

Object obj = ...; // 某个对象

if (obj instanceof String) {
    String s = (String) obj;
    System.out.println("字符串长度: " + s.length());
}

枯燥但常见的模板

这种模式非常常见——事件处理、处理异构集合、带继承的业务逻辑等。

为什么不方便

  • 代码重复——不得不在 instanceof 和强转中各写一遍类型。
  • 出错风险——很容易不小心转成错误的类型而触发 ClassCastException
  • “噪声”代码——尤其在多重检查时,可读性变差。

2. Pattern Matching for instanceof:新语法

在 Java 16 中,为 instanceof 引入了模式匹配(pattern matching)。现在可以在检查类型的同时,直接声明目标类型的变量,并在 if 分支内可用。

新语法

if (obj instanceof String s) {
    // s 已经是字符串!
    System.out.println("字符串长度: " + s.length());
}
  • instanceof 的类型后写上新变量名:String s
  • 该变量只在条件为真时所在的代码块内可见。
  • 无需写 (String) 的强转——编译器会保证安全。

“魔法”是什么?编译器会检查类型,如果匹配,就“解包”出需要类型的变量;否则分支不会执行。

在真实代码中的样子

Object obj = "你好,Java 16+!";

if (obj instanceof String s) {
    System.out.println("大写:" + s.toUpperCase());
} else {
    System.out.println("这不是字符串!");
}

3. 安全性与可读性:为什么它很棒

消除 ClassCastException 错误

Object obj = 123;
// String s = (String) obj; // 砰!抛出异常。

使用模式匹配时,变量只会在类型检查成功时创建——不存在“错误强转”。

代码更短更清晰
两行变一行。更少的“噪声”代码——更易读、更易维护。

示例:处理不同类型

public static void printInfo(Object obj) {
    if (obj instanceof String s) {
        System.out.println("字符串长度为 " + s.length());
    } else if (obj instanceof Integer i) {
        System.out.println("整数: " + (i + 1));
    } else {
        System.out.println("未知类型: " + obj);
    }
}

4. 使用示例与细节

检查多种类型

Object value = ...;

if (value instanceof String s) {
    System.out.println("这是字符串: " + s);
} else if (value instanceof Number n) {
    System.out.println("这是数字: " + n);
} else {
    System.out.println("其他内容: " + value);
}

与 null 的配合
如果对象为 null,则 instanceof 总是返回 false——不会有 NPE,但代码块也不会执行。

Object obj = null;

if (obj instanceof String s) {
    // 如果 obj == null,此块永远不会执行
    System.out.println("字符串: " + s);
} else {
    System.out.println("obj 要么是 null,要么不是字符串");
}

结合继承的模式匹配

class Animal {}
class Dog extends Animal {
    void bark() { System.out.println("汪!"); }
}

Animal a = new Dog();

if (a instanceof Dog d) {
    d.bark(); // 无需强制转换即可调用 Dog 的方法!
}

请记住,检查顺序很重要:应从更具体到更一般,否则“窄”类型的检查可能不会生效。

对比:旧方式与新方式

旧方式 新方式(模式匹配)
if (obj instanceof Cat) {
    Cat c = (Cat) obj;
    c.meow();
}
if (obj instanceof Cat c) {
    c.meow();
}

5. instanceof 模式匹配的限制

  • 变量的作用域。 模式中声明的变量只在检查为真的分支内可见。
if (obj instanceof String s) {
    System.out.println(s); // s 可用
}
// System.out.println(s); // 错误!这里看不到 s
  • 不能在一个条件中声明多个不同类型的变量。
// 编译错误:
if (obj instanceof String s || obj instanceof Integer i) {
    // ...
}
  • 需要 Java 16+。 在更旧的 JDK 版本上不支持新语法。

6. 实践示例(基于一个简单应用)

设想一个简单的 Task Manager,包含不同类型的任务。

class Task {
    String title;
    public Task(String title) { this.title = title; }
}

class BugTask extends Task {
    int severity;
    public BugTask(String title, int severity) {
        super(title);
        this.severity = severity;
    }
}

class FeatureTask extends Task {
    String feature;
    public FeatureTask(String title, String feature) {
        super(title);
        this.feature = feature;
    }
}

使用模式匹配进行处理

public static void processTask(Task t) {
    if (t instanceof BugTask bug) {
        System.out.println("缺陷: " + bug.title + ", 严重性: " + bug.severity);
    } else if (t instanceof FeatureTask feature) {
        System.out.println("特性: " + feature.title + ", 模块: " + feature.feature);
    } else if (t instanceof Task task) {
        System.out.println("普通任务: " + task.title);
    }
}

7. 一些有用的细节

表格:instanceof 的模式匹配——优缺点

优点 缺点/限制
更少的代码,更高的可读性 需要 Java 16+
无 ClassCastException 风险 变量只在 if 块内可见
编译期的类型安全 不支持在一个条件里处理多个类型
便于处理继承 在旧版 IDE 和构建环境中可能不受支持
适用于任何类

可视化示意:instanceof 的模式匹配如何工作

+---------------------------+
|      Object obj           |
+---------------------------+
            |
            v
  if (obj instanceof Type t)
            |
       是           否
    (true)       (false)
    |               |
    v               v
 t 可用         t 不存在
   (代码)         (无访问权限)

8. 使用 instanceof 模式匹配的常见错误

错误 No.1:尝试在 if 块之外使用变量。 在模式中声明了变量,离开代码块后——变量就不存在了。编译器会理直气壮地报错:“s 是谁?”

错误 No.2:以为 instanceofnull 也会成立。 如果对象为 nullinstanceof 条件总为假,变量不会创建。如有需要,请单独处理 null

错误 No.3:在旧版 JDK/IDE 中使用新语法。 在 Java 11 及以下版本中,instanceof 的模式匹配不可用——会得到语法错误。请检查 JDK 版本。

错误 No.4:对作用域的误解。 模式中的变量只在检查为真的分支内可见。在其外部——它并不存在。

错误 No.5:期望一次同时支持多种类型。 不能在一个条件里同时为两种不同类型声明变量:if (obj instanceof String s || obj instanceof Integer i)——这样不行。每种类型需要各自的检查。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION