Java中Object不能直接强转为业务类,因为强制转换仅改变引用类型,不改变对象实际类型;若obj真实类型非目标类(如LinkedHashMap),将抛ClassCastException。

Java 中 Object 转业务类为什么不能直接强转?
当从 Map、JSON.parseObject()、MyBatis 的 selectOne() 或某些泛型擦除后的 API 拿到一个 Object,你以为 (User) obj 就能还原成业务类?不一定。如果 obj 实际是 LinkedHashMap(比如 FastJSON 默认解析 JSON 字符串为 Map),强转会抛 ClassCastException。
关键点在于:强制类型转换(cast)只改变引用的编译时类型,不改变运行时对象的真实类型。它不是“还原”,而是“断言”——你得先确保底层对象确实是目标类的实例。
- 常见错误现象:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.example.User - 典型场景:用
JSON.parseObject(jsonStr, Object.class)后试图强转;或 MyBatis 查询未指定resultType导致返回Object包裹的Map - 真正需要的是“反序列化重建”,而非类型转换
用 JSON.toJSONString() + JSON.parseObject() 安全重建实体
这是最通用、侵入性最小的兜底方案,尤其适用于已知原始数据结构但类型信息丢失的情况。
- 先确认
obj是可序列化的(如Map、List或已有字段值的 POJO) - 把它转成 JSON 字符串,再用明确的目标类重新解析:
User user = JSON.parseObject(JSON.toJSONString(obj), User.class);
- 注意:若
obj是 null 或非标准结构(如含循环引用),会失败;生产环境建议加try-catch - 性能影响:两次序列化/反序列化,小数据无感,高频调用需权衡
MyBatis 场景下避免 Object 返回,优先用泛型接口
很多 Object 问题其实源于 Mapper 接口定义不当。MyBatis 3.4+ 完全支持泛型方法,无需手动转型。
- 错误写法:
Object selectById(Long id);→ 返回Map或代理对象,强转风险高 - 正确写法:
,并在 XML 中指定T selectById(@Param("id") Long id); resultType="com.example.User" - 更稳妥:用
@Select("SELECT * FROM user WHERE id = #{id}")注解 + 显式返回类型User selectById(Long id); - 如果必须用
Object(如动态 SQL 多类型结果),应在 service 层用BeanUtils.copyProperties()或构造器初始化新对象,而不是强转原Object
Spring Boot 中 RestTemplate 返回 Object 怎么办?
RestTemplate.getForObject(url, Object.class) 是典型的“类型擦除陷阱”。它返回的是 LinkedHashMap,不是你的实体类。
- 永远不要对它的返回值做
(User) response—— 必崩 - 正确做法:直接指定目标类型:
restTemplate.getForObject(url, User.class) - 若 URL 返回结构不确定(如统一响应体
{ "code": 0, "data": { ... } }),应定义封装类(如Response),并用ParameterizedTypeReference:Response<user> res = restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<response>>() {}).getBody();</response></user> - 别依赖
ObjectMapper.convertValue()对LinkedHashMap强转——它内部也是靠反射设值,但不如直接解析 JSON 稳定
最容易被忽略的一点:所谓“还原”从来不是靠 cast 实现的,而是靠数据重建或类型声明前置。一旦看到 Object,第一反应不该是“怎么转”,而是“为什么它是 Object”——多数时候,改调用方式比写转换逻辑更可靠。










