最近在幫人調試代碼的時候,發現了這樣一個問題: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