最近在开发中遇到一个现象,就是在编译时整个代码中使用了泛型,并没有出现任何类型转换上的问题。代码如下:
[code]
void foo(List<ADto> res) {
if(res != null) {
List<Integer> resIds = new ArrayList<Integer>();
for (ADto a : res) {//在这一行报java.lang.ClassCastException
resIds.add(a.getId());
}
}
//do sth
}
[/code]
然而程序在运行时,总是在for循环处报java.lang.ClassCastException,也就是类型转换异常。根据Java的语义来讲,这是一个不应该发生的错误异常。
因为这是一个高并发程序,使用了Memcached等缓存,所以根据经验,很容易能够判断出来,无论如何,res都是从缓存中取出来的旧的集合数据,而非其他可能。幸好我还记得几天前的代码中的res中放置的是其他类型的数据。so,开始清除缓存,之后再也未出现ClassCastException这个异常报错了。
通过这个案例,使我们认识到,泛型仅仅是JDK5之后引入的一个编译时级别上的判断和支持。进入运行时,如果方法中传入的实参并未遵循泛型的约束,程序默认不会报错,只有运行到实际类型转换时,才会抛出或者捕获这个异常,然后导致程序在运行时失败。由于泛型仅仅是编译时级别上的支持,就非常容易在程序运行时造成更大的困惑。
从这个层面来看,泛型的引入,并未很好的解决java运行时所带来的类型转换问题,或者说,泛型的引入,并不是为了解决整个程序从编译时到运行时的全部类型转换的问题,泛型仅仅是为了解决编译时的类型转换而生。那么这样的做法,对于java从1.4版就已经比较成型的语言,到jdk5的引入泛型后的彻底类库大翻新,到底是利大于弊,还是弊大于利呢?
[code]
void foo(List<ADto> res) {
if(res != null) {
List<Integer> resIds = new ArrayList<Integer>();
for (ADto a : res) {//在这一行报java.lang.ClassCastException
resIds.add(a.getId());
}
}
//do sth
}
[/code]
然而程序在运行时,总是在for循环处报java.lang.ClassCastException,也就是类型转换异常。根据Java的语义来讲,这是一个不应该发生的错误异常。
因为这是一个高并发程序,使用了Memcached等缓存,所以根据经验,很容易能够判断出来,无论如何,res都是从缓存中取出来的旧的集合数据,而非其他可能。幸好我还记得几天前的代码中的res中放置的是其他类型的数据。so,开始清除缓存,之后再也未出现ClassCastException这个异常报错了。
通过这个案例,使我们认识到,泛型仅仅是JDK5之后引入的一个编译时级别上的判断和支持。进入运行时,如果方法中传入的实参并未遵循泛型的约束,程序默认不会报错,只有运行到实际类型转换时,才会抛出或者捕获这个异常,然后导致程序在运行时失败。由于泛型仅仅是编译时级别上的支持,就非常容易在程序运行时造成更大的困惑。
从这个层面来看,泛型的引入,并未很好的解决java运行时所带来的类型转换问题,或者说,泛型的引入,并不是为了解决整个程序从编译时到运行时的全部类型转换的问题,泛型仅仅是为了解决编译时的类型转换而生。那么这样的做法,对于java从1.4版就已经比较成型的语言,到jdk5的引入泛型后的彻底类库大翻新,到底是利大于弊,还是弊大于利呢?