向下转型必须先用 instanceof 检查运行时类型,再安全强转;优先使用具体泛型、通配符约束和多态替代强制转换,从设计上减少转型需求。

在继承关系下做类型转换,关键不是“能不能转”,而是“该不该转”和“有没有保障”。最常出问题的是向下转型(父类引用转子类实例),不加检查直接强转必然引发 ClassCastException。核心对策是:先确认运行时真实类型,再安全转换。
向下转型前必须用 instanceof 检查
这是最直接、最常用的防御手段。JVM 不会在编译期阻止你写 (Dog) animal,但运行时若 animal 实际是 Cat 或 Animal 本身,就会崩溃。
-
正确写法:
if (animal instanceof Dog) { Dog dog = (Dog) animal; } - 别省略这步:哪怕你“确定”它应该是 Dog,只要引用类型是父类,运行时类型就可能不同——尤其来自集合、反射、反序列化等场景
-
注意 null 安全:
instanceof对null返回false,不会 NPE,所以无需额外判空
用泛型+通配符减少裸类型强转
集合里存父类、取出来硬转子类,是 ClassCastException 的高发区。根源是泛型擦除后失去类型信息,比如 List<Animal> 在运行时就是原始 List。
-
优先声明具体泛型:用
List<Dog>而非List<Animal>接收 Dog 实例,避免后续转型 -
读取时用通配符约束:如需统一处理多种子类,可用
List<? extends Animal>,配合instanceof分支处理 -
避免原始类型:不用
List list = new ArrayList(),这种写法等于主动放弃编译期类型保护
封装安全转型工具方法
重复写 if (x instanceof T) return (T) x; 易出错且冗余。可提取为泛型工具方法,兼顾可读性与复用性。
立即学习“Java免费学习笔记(深入)”;
-
基础版:
public static <T> T safeCast(Object obj, Class<T> type) { return type.isInstance(obj) ? type.cast(obj) : null; } -
严格版(抛异常):像资料中提到的,校验失败时抛
IllegalStateException,比静默返回 null 更利于暴露设计问题 - 适用场景:JSON 反序列化后转业务对象、SPI 扩展点加载、框架回调参数解析等不确定类型的环节
从设计上减少向下转型需求
频繁出现 “我要把 Animal 转成 Dog 才能调 fetch()” 是代码坏味道。说明职责没有合理分配,或抽象不够到位。
-
用多态代替转型:把
fetch()提到Animal中(默认空实现或抛 UnsupportedOperationException),子类按需重写 - 引入访问者模式或策略接口:当行为差异大且无法统一到父类时,用组合替代强制转型
- 审查 API 边界:对外暴露父类引用是好的,但内部逻辑动不动就 downcast,大概率意味着模块职责过重或契约不清


















