instanceof 判断运行时实际类型而非声明类型,如 Animal a = new Dog() 时 a instanceof Dog 为 true;它返回 boolean、不自动转换、不处理 null 和基本类型,且受泛型擦除影响。

instanceof 判断的是运行时实际类型,不是声明类型
你写 Animal a = new Dog(),编译器只知道 a 是 Animal 类型,但 a instanceof Dog 仍为 true——因为 JVM 在运行时能拿到对象头里的真实类信息。这正是多态下做分支逻辑的基础。
常见错误是误以为“父类引用就只能当父类用”,结果绕开 instanceof 直接强转,一跑就抛 ClassCastException。比如 (Dog) a 在 a 实际是 Cat 时必然失败。
- 子类实例
instanceof父类 →true - 父类实例
instanceof子类 →false(永远不成立) -
null instanceof Xxx→false,不抛异常,但容易被忽略 - 右边必须是编译期可见的类或接口,不能是
String.class或字符串字面量
必须配合显式强制转换,JVM 不会自动帮你转
instanceof 只返回 boolean,它不改引用类型,也不生成新变量。检查通过后,你还得自己写 (TargetType) obj 才能调用子类特有方法。
典型安全模式就是“先判后转”:
if (obj instanceof String) {
String s = (String) obj; // 这一行不能省
System.out.println(s.length());
}
别指望 instanceof 做完事就自动给你一个 String 变量——那是 Java 14+ 模式匹配的语法糖,老版本不支持。
- Java 14 起可用
if (obj instanceof String s),s自动绑定且作用域限于该if块内 - 但需开启预览特性:
javac --enable-preview --source 14,生产环境慎用 - 没升级 JDK 的项目,老老实实写两行:判断 + 强转
泛型擦除后,instanceof 只能写原始类型
像 List 这种带泛型的类型,运行时已擦除成 List。所以 list instanceof List 编译直接报错,只能写 list instanceof List。
这意味着你无法靠 instanceof 区分 List 和 List——它们在运行时都是 List。如果真要校验元素类型,得遍历或结合其他手段(如反射取泛型签名,但不可靠)。
- 数组例外:
new String[0] instanceof String[]合法,数组类型保留 - 接口检查不受影响:
obj instanceof Serializable依然有效 - 密封类(sealed)下,
instanceof行为不变,但 IDE 可能提示“未覆盖所有子类型”
容易被忽略的 null 和基本类型陷阱
instanceof 对 null 返回 false,看似安全,但如果你的逻辑依赖“非 null 且是某类型”,就得额外判空,否则可能进错分支。比如:
if (obj instanceof String) {
// obj 为 null 时这里根本不会执行
// 但如果你本意是“处理 String 或 null”,就得拆成两个 if
}
另一个硬性限制:左边可以是任意引用类型,但右边绝不能是基本类型。写 42 instanceof Integer 编译失败;i instanceof int 更是语法错误——int 不是类,没有运行时类对象。
- 基本类型包装类可以:
Integer.valueOf(42) instanceof Integer→true - 想统一处理原始值和包装类?得靠
Objects.equals(obj.getClass(), Integer.class)或别的方案 - 模块化(JDK 9+)下,若目标类未导出,
instanceof会因类不可见而编译失败,不是运行时问题
实际写的时候,最常漏掉的是对 null 的单独处理,以及泛型擦除后还试图用参数化类型做判断。这两处不注意,代码看着能编译,跑起来要么跳过逻辑,要么根本走不到预期分支。










