最近在帮人调试代码的时候,发现了这样一个问题:java
工程是Spring Boot + Mybatis,主要代码以下:sql
xxxMapper.xml:mybatis
<resultMap id = "BaseResultMap" type = "aaa.bbb.ccc.xxxVo"> <id column="id" jdbcType="Integer" property="id" /> ... </resultMap> <select id="selectSomething" resultMap="BaseResultMap"> select id, xxx ... from where </select>
xxxMapper.java:app
package ... import ... public interface xxxMapper { List<yyyVo> selectSomething(); ... }
xxxServiceImpl.java:ide
package ... import ... @Serivce public class xxxSerivceImpl implements xxxService { @Autowired private xxxMapper xxxDao; @Override Result selectSomething(){ ... List<yyyVo> list = xxxDao.selectSomething(); foreach(yyyVo yyy : list){ yyy.getSth(); } } ... }
你们应该已经发现了:SQL的返回值在xxxMapper.xml中被定义为xxxVo,可是在xxxMapper.java之中却被定义为List<yyyVo>,而且在后面的service层使用该方法时,也把返回结果看成List<yyyVo>来操做。但奇怪的是,当sql执行结束并把结果赋值给List<yyyVo>时,并无报错,只有当for循环中取list的每一项的值的时候,才会抛出class cast Exception。调试
这个状况有点奇怪,主要缘由是Java在处理泛型的时候进行了类型擦除。编译器关注的只有xxxServiceImpl中的code
List<yyyVo> list = xxxDao.selectSomething();
对于编译器而言,这一个赋值语句的左右两端都是List<yyyVo>,因此能够正常编译经过。xml中对sql返回的数据类型定义为xxxVo的状况根本不被编译器探测到。在执行代码时,因为泛型内部的类型是擦除的。因此mybatis把返回的数据组成List<xxxVo>赋值给list的时候,由于双方都是List<>,也能正常执行。只有当程序从list中取出数据时,由于代码中认为list的每一个数据都应该是yyyVo,而实际的list时xxxVo,所以产生了class cast Exception。xml