java类型转换分编译时和运行时两阶段:编译时校验声明类型兼容性,运行时通过checkcast指令检查对象真实类型,泛型擦除后仍保留运行时类型检查,instanceof用于安全探测类型。

Java 的类型转换不是“一转了事”,而是分两个阶段完成的:编译时看声明是否合理,运行时看对象是否真能转。这两个阶段各司其职,缺一不可。
编译时校验:只认声明,不看实际
编译器(javac)只根据变量的声明类型做静态判断,不管它背后真正指向什么对象:
- 向上转型(如 Object o = new String();)永远允许,因为子类天然兼容父类,不需要写强制转换
- 向下转型(如 String s = (String) o;)必须显式加括号,且编译器要能确认 o 的声明类型和 String 之间存在继承关系(比如是 Object 或 CharSequence)
- 完全无关的类型(如 String 和 Integer)哪怕运行时想用字符串解析,编译也直接报错——这不是类型转换,是业务逻辑转换
运行时检查:对象说了算
字节码里,向下转型会生成 checkcast 指令。JVM 执行时查对象头里的真实类型信息:
- 如果对象真是 String,转成 Object 或 Comparable 都成功
- 如果对象其实是 ArrayList,却硬要转成 String,立刻抛 ClassCastException
- null 可以被转成任意引用类型(不触发 checkcast),但后续调用方法会崩在 NullPointerException
泛型擦除后,类型检查没消失
泛型在编译后被擦除(List
- 写 String s = list.get(0);,等价于 String s = (String) list.get(0);
- 这个强转仍走运行时 checkcast 流程——若 list 实际存了 Integer,照样抛异常
- 所以泛型只帮你挡住编译期错误,不改变运行期类型安全的本质
instanceof 是安全探路者
instanceof 不是转换操作,而是类型探测工具,底层也用类似 checkcast 的机制,但只返回真假:
- 对 null 返回 false,不会抛异常
- 右边必须是具体类或接口(不能是泛型变量 T)
- 常和向下转型配合使用:if (obj instanceof String) { String s = (String) obj; },避免无谓的异常开销











