概述
Java的类型转换异常(ClassCastException),恐怕是开发中最常见的异常之一,比如你把一个本身为String的对象强行转换成List时,就会抛出此异常。当然,一般情况下这种错误很容易就从异常信息中发现原因并纠正,通常对于此类问题我们的想法就是:class文件相同,即字节码相同,那么实例化产生的对象肯定也会相同类型。但是,存在一些情况,会发生形如“把class1转换成class1却抛出类型转换异常”的情况
先看一个例子,包含三个源文件:MainClass,ClassOne,ClassTwo 。MainClass是程序入口,另外两个类用于测试,代码很简单,如下






































































如果按固有的思维,则 c2_obj 传入 doTest方法后,执行 ClassTwo c2 = (ClassTwo)obj; 是没问题的,但是实际运行则会抛出 ClassCastException ,并明确的告诉你 “ClassTwo c2 = (ClassTwo)obj”有问题,为什么呢?
原因在于使用了不同的类加载器载入各个类。其中,main函数中,ucl1载入的是ClassTwo,而ucl2在载入ClassOne时,由于ClassOne内部引用了ClassTwo,ucl1会把ClassTwo也一起加载进来,这样VM就有了两个ClassTwo,分别对应不同的类加载器。对于ClassOne.doTest() 中的“ ClassTwo c2 = (ClassTwo)obj”这句代码,c2 的类型全称是“ucl2加载的test.jboss.jmx.classCastEx.ClassOne”
现在我们应该明白了,之所以会有类型转换异常,是由于类在VM中的签名不仅仅是类的完整包名,还包括载入它的类加载器。上述例子中,由ucl1加载的ClassTwo,作为参数传入由ucl2加载的ClassOne.doTest() 中,自然就与 c2 的类型不符合了,导致无法转换
也许你一般不会用这种“古怪”的方式加载类,通常我们都是把需要的外部类写入项目的classpath,现在的IDE也提供非常方便的手段导入外部类。但是想象一下在应用服务器容器中,你部署的多个应用都可能共享某个jar库的类实例。当重新部署包含该jar的应用时,所有相关的应用都必须刷新一遍,否则很容易出现上述问题
PS:本文参考了《JBOSS 4.0 标准教材》中的内容,书中提供了相应源码解释这个问题,不过比较繁琐,上面的代码是我简化过的,在我的机子上试验成功。请不要将ClassOne 和 ClassTwo 与MainClass放在一个项目中,那样在运行之前就会预先加载项目中所有的类,等于ClassOne 和 ClassTwo都由VM先加载了,就不会出现预期的转换异常了。可以将ClassOne 和 ClassTwo在另一个项目中编写然后打包,放到MainClass所在项目的根目录
最后
以上就是可耐仙人掌为你收集整理的ClassLoader引发的类型转换异常的全部内容,希望文章能够帮你解决ClassLoader引发的类型转换异常所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复