集合泛型不匹配导致的ClassCastException异常
推荐
在线提问>>
一. 代码重现
前几天有个学生编写集合代码时,运行的结果中却出现了一个自己没见过的异常,他不知道怎么解决,于是就跑来找老师帮忙。下面就是的代码,大家可以来看看,如下所示:
上述代码,一旦运行就会出现下图中的异常现象。说实话,对老师来说,只要一遇到bug,真是瞬间感觉连吃大盘鸡都不香了,必须立马盘它才行。
上图中,我们看到了一个叫做ClassCastException类型转换的异常!为什么会出现这个bug呢?其实如果我们仔细检查一下代码,就会发现原来是集合中的值写错了!我们声明的集合泛型是Double类型的,结果添加数据元素的时候,给集合添加了一个整型的元素,这样就造成了上述异常。而且根据错误信息的提示,异常出现在代码的第40行位置,现在我们知道了异常的原因和位置,接下来解决就容易了。
二. bug分析
其实上述代码中之所以会出现问题,是因为集合对泛型的严格要求所导致的。一开始学生觉着int类型可以直接转换为double类型,所以就往集合中添加了整型数据。但实际上Java中的集合泛型,要求的必须是包装类,我们的代码中就是Interger和Double,所以是无法将基本类型直接转为包装类型的。但学生却不明白,为什么基本类型与包装类型两者的类型不一致,但在往集合中添加数据时却可以添加进去呢?为了给学生讲明白这个问题,就通过javap命令带学生查看了反编译后的List类型,我们来看看泛型的底层究竟是个什么情况,如下图所示:
通过反编译可以看出,集合在底层编译时,其实所谓的泛型都被擦除了。也就是说,当我们在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。所以List和List在运行时事实上是相同的类型。而这其中原始类型的集合是特别容易出问题的,因为原始类型会跳过泛型检查且很不安全。