記一次由於Java泛型類型擦除而導致的問題,及解決辦法


中所周知,Java中的泛型並不像C++、C#一樣是真正的泛型,其泛型是通過類型擦除來實現的。具體什么是類型擦除,可以參看這篇博文:http://icyfenix.iteye.com/blog/1021949。今天要記錄的是在實際開發中遇到的一個,由於Java這種泛型的實現方式而導致的問題,及解決辦法。

 

一下代碼是模擬真實開發環境下的實現:

 1   @Test
 2   public void test(){
 3     // 構建searchMap,模擬前端傳來的查詢參數
 4     Map<String, Object> searchMap = new HashMap<String, Object>();
 5     List<Integer> goodsIds1 = new ArrayList<Integer>();
 6     goodsIds1.add(1);
 7     goodsIds1.add(2);
 8     goodsIds1.add(3);
 9     searchMap.put("goodsIds", goodsIds1);
10     searchMap.put("goodsType", 1); 
11     
12     // 利用searchMap進行查詢,模擬后端的邏輯
13     List<Long> goodsIds2 = (List<Long>)searchMap.get("goodsIds");
14     for(Long goodsId : goodsIds2){
15       System.out.println(goodsId);
16     }
17   }

這里的searchMap用來接收前端傳來的查詢商品信息的參數,假設要查詢商品id分別為1、2、3,同時商品類型為1的商品。后端邏輯會從searchMap中獲取goodsIds的list,然后循環查詢每一個商品的信息。以上代碼在eclipse中不會提示任何錯誤,但其實在運行的時候會拋出  java.lang.ClassCastException 異常。

 

問題就在於第9行

searchMap.put("goodsIds", goodsIds1);

中goodsIds1是List<Integer> 類型的,而第13行

List<Long> goodsIds2 = (List<Long>)searchMap.get("goodsIds");

在取出goodsIds的時候,雖然強制轉換為List<Long>型,但實質上,goodsIds2中的值為Integer型,如下圖:

所以在第14行遍歷goodsIds2的時候

for(Long goodsId : goodsIds2){
    System.out.println(goodsId);
}

就會拋出 java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long 異常。這里本質就是由於List<Integer>和List<Long>,在編譯之后,其泛型信息都被擦除,都被視為List,所以取出時能夠轉換成功。

 

其實在第13行,IDE會給出警告:Type safety: Unchecked cast from Object to List<Long>,雖然可以通過在方法上加注解:@SuppressWarnings("unchecked")來消除警告,但這只是起到標示作用,並不會修正錯誤。最簡單的修復的辦法就是將goodsIds2也聲明為List<Integer>,然后再遍歷的時候轉為Long型,但是不太優雅。另外一種解決方法就是,用Java類去接收前端傳來的參數,而不是用Map,但是這樣的話需要增加一個POJO類。那為什么不直接將goodsIds1也聲明為List<Long>型呢?像這樣:

 1   @Test
 2   public void genericTest(){
 3     // 構建searchMap,模擬前端傳來的查詢參數
 4     Map<String, Object> searchMap = new HashMap<String, Object>();
 5     List<Long> goodsIds1 = new ArrayList<Long>();
 6     goodsIds1.add(1L);
 7     goodsIds1.add(2L);
 8     goodsIds1.add(3L);
 9     searchMap.put("goodsIds", goodsIds1);
10     searchMap.put("goodsName", "商品1"); 
11     
12     // 利用searchMap進行查詢,模擬后端的邏輯
13     List<Long> goodsIds2 = (List<Long>)searchMap.get("goodsIds");
14     for(Long goodsId : goodsIds2){
15       System.out.println(goodsId);
16     }
17   }

這樣做確實能夠通過測試,但在實際開發中,用Map<String, Object>去接收到的參數,當數值小於Integer的最大值時,會默認將其按Integer處理。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM