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