instanceof 必须在转型前使用,否则可能抛出 ClassCastException;它对 null 返回 false,但泛型擦除使其无法检查参数化类型,接口检查需关注实际运行时实现而非源码声明。
instanceof 检查必须在转型前做,否则可能抛
转型(cast)本身不检查类型安全性,JVM 只在运行时真正用到该引用时才校验。如果跳过
直接强转,一旦对象不是目标类型,就会在执行到那行时崩出
——这个异常无法靠编译器提前发现。
实操建议:
所有非泛型容器(比如
、
)里取出来的元素,在转型前都应先用
判断
不要依赖“我确定它就是这个类型”这种假设,尤其当数据来自外部输入、反射或旧代码时
对
返回
,所以无需额外判空;但若你后续逻辑依赖非空,仍需单独处理
注意泛型擦除后
不能检查泛型参数
Java 泛型在编译后被擦除,
只能检查原始类型,不能检查带泛型的类型字面量。比如
是非法语法,编译不过。
实操建议:
只能写
,不能加
若需确认泛型内容,得靠遍历 + 元素级
,例如:先确认是
,再对第一个元素做
使用
也受同样限制,它和
行为一致,只是动态版
接口类型检查要小心实现类未显式声明的情况
对接口有效,但前提是运行时对象实际实现了该接口。有些类通过代理、ASM 或序列化框架生成,可能没在源码里写
,但运行时确实支持——这时
仍会返回
;反之,若仅继承了某个实现类却未重写关键方法,也可能被误认为符合接口语义,但这是设计问题,不是
的锅。
实操建议:
检查接口时,确保你关心的是“能否调用某组方法”,而不是“源码是否写了 implements”
避免用
替代业务逻辑判断,比如“是不是管理员”不该靠
,而应查角色字段
对接口检查后仍需考虑方法是否真可安全调用(比如某些实现可能抛
)
替代方案:Optional + 方法引用比裸
更健壮
硬写
容易漏掉分支、重复 cast、或者把逻辑散落在多处。现代写法更倾向封装行为而非类型。
实操建议:
用
把检查+转型+空处理链在一起
对常见转换场景(如转数字),优先用工具方法:
比
更安全
如果转型后只调一个方法,直接用
或反射 +
可能比反复检查更轻量,但要权衡可读性
类型检查不是为了满足语法,而是为了守住运行时边界。最常被忽略的一点是:即使
返回
,也不能保证转型后的对象处于可用状态——比如反序列化失败的对象,类型对了,字段却是 null。
ClassCastExceptioninstanceofClassCastExceptionListObject[]instanceofinstanceofnullfalseinstanceofinstanceoflist instanceof ArrayListlist instanceof ArrayListinstanceofArrayListitem instanceof StringClass.isInstance()instanceofinstanceofimplements Xinstanceoftrueinstanceofinstanceofuser instanceof AdminUserUnsupportedOperationExceptioninstanceofif (obj instanceof String) { s = (String) obj; }Optional.ofNullable(obj).filter(String.class::isInstance).map(String.class::cast)NumberUtils.toInt(str, 0)if (s instanceof String) Integer.parseInt((String)s)MethodHandletry/catchinstanceoftrue