当前位置: 安卓之星 -> Java开发 -> 记一次由于Java泛型类型擦除而导致的问题,及解决办法

记一次由于Java泛型类型擦除而导致的问题,及解决办法

作者:网络 发表于: 2016-12-06 点击: 443 次

今天要记录的是在实际开发中遇到的一个,由于Java这种泛型的实现方式而导致的问题,及解决办法。
一下代码是模拟真实开发环境下的实现:
@Test
public void test(){
     // 构建searchMap,模拟前端传来的查询参数
     Map<String, Object> searchMap = new HashMap<String, Object>();
     List<Integer> goodsIds1 = new ArrayList<Integer>();
     goodsIds1.add(1);
     goodsIds1.add(2);
     goodsIds1.add(3);
     searchMap.put(“goodsIds”, goodsIds1);
     searchMap.put(“goodsType”, 1); 
     
     // 利用searchMap进行查询,模拟后端的逻辑
     List<Long> goodsIds2 = (List<Long>)searchMap.get(“goodsIds”);
     for(Long goodsId : goodsIds2){
       System.out.println(goodsId);
     }
}
这里的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型,如下图:

goodsids

所以在第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>型呢?像这样:
@Test
 public void genericTest(){
     // 构建searchMap,模拟前端传来的查询参数
     Map<String, Object> searchMap = new HashMap<String, Object>();
     List<Long> goodsIds1 = new ArrayList<Long>();
     goodsIds1.add(1L);
     goodsIds1.add(2L);
     goodsIds1.add(3L);
     searchMap.put(“goodsIds”, goodsIds1);
     searchMap.put(“goodsName”, “商品1”); 
     
     // 利用searchMap进行查询,模拟后端的逻辑
     List<Long> goodsIds2 = (List<Long>)searchMap.get(“goodsIds”);
     for(Long goodsId : goodsIds2){
       System.out.println(goodsId);
     }
}
这样做确实能够通过测试,但在实际开发中,用Map<String, Object>去接收到的参数,当数值小于Integer的最大值时,会默认将其按Integer处理。

相关文章

相关文章

赶快留言冒泡

  • 评论 (0)
  • 引用通告 (0)
目前还没有任何评论.
目前还没有任何Trackbacks和Pingbacks.
吐个泡浮上去.