必须先用 instanceof 判断再强制转换,否则易抛 ClassCastException;因编译器只认声明类型,JVM 运行时才校验实际类型,instanceof 可安全探针真实继承关系且天然防 null。

必须先用 instanceof 判断,再执行强制转换。跳过这一步直接转型,是 ClassCastException 最常见的根源。
为什么一定要先判后转
编译器只认变量声明类型,不查实际对象类型。比如 Object obj = new Cat(),声明是 Object,但实际是 Cat;若你写 (Dog) obj,JVM 运行时发现它根本不是 Dog 或其子类,立刻抛异常。
- instanceof 在运行时检查对象的真实类继承链,返回 true 表示“确实是该类型或其子类”,此时强转才合法
- 对 null 返回 false,不会触发 NullPointerException,天然防空指针
- 它不改变对象、不抛异常、无副作用,就是纯粹的“安全探针”
标准写法:判断和转换必须在同一个作用域内
正确姿势是把转型操作放在 if 块内部,确保只在确认类型后才执行:
- ✅
if (obj instanceof Dog) { Dog d = (Dog) obj; d.bark(); } - ❌
Dog d = (Dog) obj;—— 没判断,风险直接暴露 - ❌
if (obj instanceof Dog) { } Dog d = (Dog) obj;—— 判断和转换脱节,中间可能被修改
Java 14+ 推荐用模式匹配写法
新版支持一步到位:判断 + 转换 + 变量声明合并为一行,更简洁且作用域清晰:
if (obj instanceof Dog dog) { dog.bark(); }- 此时
dog已自动完成非空校验和类型转换,块外不可见,杜绝误用 - 注意:目标类需是 final 类或密封类(sealed class),普通类也支持,但部分 IDE 提示可能受限
常见陷阱与避坑要点
-
不能用于基本类型:如
int i = 5; i instanceof Integer编译失败;需用包装类,如Integer i = 5; i instanceof Integer -
泛型擦除后无法检查参数化类型:
obj instanceof List<String>是语法错误;只能写obj instanceof List -
接口检查只保类型兼容,不保行为可用:比如
obj instanceof List成立,不代表能调用add()——Arrays.asList()返回的就是不可变 List - 别和 getClass() == 混用:前者接受子类(多态友好),后者只认本类(精确匹配),选错会导致逻辑漏判

















