“类型擦除”的解决方案及原因
今天是我第一次遇到这个 ‘类型擦除’ 的情况,请教了有丰富的Java开发经验的同事,他告诉我说,是JVM底层对我们封装的对象类型进行了擦除,把我们的类型替换了。
产生原因
Java在编译后的字节码(.class)文件中是不包含泛型中的类型信息的,使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。这就是类型擦除。如在代码中定义的List<
Object>
和List<
String>
等类型,在编译之后都会变成List,JVM看到的只是List。
当JVM擦除了我们原本封装的对象时,我们在运行的时候会发生异常,报错为:java.lang.ClassCastException 类型转换异常
大家可以看一下我的对象的封装:
把 UserInfo 封装到 map 里
@RequestMapping("verify/{token}")
public Map<String, Object> verify(@PathVariable("token") String token){
UserInfo userInfo = userService.verify(token);
HashMap<String, Object> map = new HashMap<>();
map.put("user",userInfo);
return map;
}
在这里把从map中取出来
String token = getToken(request);
Map<String, Object> map = null;
if (StringUtils.isNotEmpty(token)) {
map = userFeignClient.verify(token);
}
if (null != map) {
//已登录,并且把用户信息放到,放行
UserInfo user = (UserInfo) map.get("user");
Long userId = user.getId();
request.mutate().header("userId",userId+"").build();
exchange.mutate().request(request);
return chain.filter(exchange);
}
在取的时候发生了“类型擦除”,报错了:java.lang.ClassCastException : java.util.LinkedHashMap cannot be cast to com.atyunli.gmall.model.user.UserInfo
于是我Debug启动查看:
实际上,value应该是我的UserInfo对象。
解决方案
发生类型擦除之后,就把JVM更改的类型转换成自己需要的类型就可以了。可以先把它转成Object 类型,因为它是所有类的父类JVM不可能对它进行封装,再把 Object 转换成 json字符串,把json字符串 转换成 我们需要的类型的对象,利用JSONObject.parseObject()这个方法。
总结:【先转成 Object -> json字符串 -> JSONObject.parseObject() 方法转成我们需要的对象】
这是我更改完的代码,其实就是把value的类型转换成我们自己需要的类型就可以了。
if (null != map) {
//先用object
Object user = map.get("user");
//在将object转化为string
String userString = JSON.toJSONString(user );
// 再将string转化为UserInfo
UserInfo userInfo = JSONObject.parseObject(userString, UserInfo.class);
Long userId = userInfo.getId();
request.mutate().header("userId",userId+"").build();
exchange.mutate().request(request);
return chain.filter(exchange);
}
总结:
先转成 Object -> json字符串 -> JSONObject.parseObject() 方法转成我们需要的对象
即使每天忙忙碌碌,也不能忘记留下美好的瞬间,也不能忘记要学习,一点点积累。一起努力学习吧,成为更优秀的程序媛~~