ClassLoader引发的类型转换异常

news/2024/7/11 0:13:43 标签: JBoss, 应用服务器, IDE, .net, Blog

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

.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" /> ClassOne.java
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
-----------------------------------------------
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
package  test.jboss.jmx.classCastEx;
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif" alt="" align="top" />.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif" alt="" align="top" />Class ClassOne
... {
.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" alt="" align="top" /> 
public void doTest(Object obj)...{
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  ClassTwo c2 
= (ClassTwo)obj;
.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" /> }

.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />
.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif" alt="" align="top" />}

.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
------------------------------------------------
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />ClassTwo只是一个空类
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
------------------------------------------------
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />MainClass.java
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
------------------------------------------------
.net/syntaxhighlighting/OutliningIndicators/None.gif" alt="" align="top" />
.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif" alt="" align="top" />.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif" alt="" align="top" />
public   class  MainClass  ... {
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />
.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" alt="" align="top" /> 
/** *//**
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  * 
@param args
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  * 
@throws MalformedURLException 
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  * 
@throws ClassNotFoundException 
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  * 
@throws IllegalAccessException 
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  * 
@throws InstantiationException 
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  * 
@throws NoSuchMethodException 
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  * 
@throws InvocationTargetException 
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  * 
@throws SecurityException 
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  * 
@throws IllegalArgumentException 
.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />  
*/

.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" alt="" align="top" /> 
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException ...{
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
// ClassOne 和 ClassTwo打包到一个jar中,名为“test.jar”,放在 MainClass 所在项目的根目录下
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
// 注意,ClassOne 和 ClassTwo 不能和MainClass放在一个项目中,后面 有解释
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
// 自定义一个类加载器,从外部导入ClassOne 和 ClassTwo
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />
  File jar = new File("test.jar");
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  System.out.println(jar.exists());
.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" alt="" align="top" />  URL[] url 
= ...{jar.toURL()};
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  System.out.println(url[
0]);
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  URLClassLoader ucl1 
= new URLClassLoader(url);
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  Class classTwo 
= ucl1.loadClass("test.jboss.jmx.classCastEx.ClassTwo");
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
//查看是否成功地利用反射机制,将ClassTwo导入进来,并显示其在VM中的hash码
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
// getClassLoader()正常情况返回classTwo的类加载器,也就是上面的 ucl1 ,如果不是,则有问题
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />
  System.out.println("hash of layout1:"+classTwo.hashCode()+"ucl "+classTwo.getClassLoader());
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
//创建一个ClassTwo的实例
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />
  Object c2_obj = classTwo.newInstance();
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
// 同理,用另一个类加载器(ucl2)载入ClassOne
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />
  File jar2 = new File("test.jar");
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  System.out.println(jar2.exists());
.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" alt="" align="top" />  URL[] url2 
= ...{jar2.toURL()};
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  URLClassLoader ucl2 
= new URLClassLoader(url2);
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  Class classOne 
= ucl2.loadClass("test.jboss.jmx.classCastEx.ClassOne");
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  Object c1_obj 
= classOne.newInstance();
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
//利用反射,调用ClassOne的 doTest 方法,将上面创建的 c2_obj 作为方法的参数
.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" alt="" align="top" />
  Class[] type = ...{Object.class};
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  Method m 
= classOne.getMethod("doTest", type);
.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif" alt="" align="top" />  Object[] para 
= ...{c2_obj};
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  m.invoke(c1_obj, para);
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />  
.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" /> }

.net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />

 .net/syntaxhighlighting/OutliningIndicators/InBlock.gif" alt="" align="top" />
如果按固有的思维,则 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所在项目的根目录。

 

http://blog.csdn.net/wangchengsi/archive/2008/02/21/2110647.aspx


http://www.niftyadmin.cn/n/1313705.html

相关文章

复习一下排序算法

因为找实习时候碰见笔试题出算法题的,在这里复习一下学习过的排序算法的思路。(以数组理思路) 算法性能: 算法的稳定性:如果Ai Aj,排序前Ai在Aj之前,排序后Ai还在Aj之前,则称这种排…

Javascript和PHP中网址编码函数的对比

原文: http://中国人民_-.!#$%^&*() ---------------------------JavaScript------------------------------ 【escape】: http%3A//%u4E2D%u56FD%u4EBA%u6C11_-.%21%23%24%25%5E%26*%28%29 【encodeURI】: http://%E4%B8%AD%E5%9B%BD%E4%BA%BA%E6%B0%91_-.!#…

Decorator Pattern

Decorator模式简介  Decorator模式又名包装器(Wrapper),它的主要用途在于给一个对象动态的添加一些额外的职责。与生成子类相比,它更具有灵活性。有时候,我们需要为一个对象而不是整个类添加一些新的功能,比如,给一个…

static_cast、dynamic_cast、reinterpret_cast、和const_cast

static_cast、dynamic_cast、reinterpret_cast、和const_cast关于强制类型转换的问题,很多书都讨论过,写的最详细的是C 之父的《C 的设计和演化》。最好的解决方法就是不要使用C风格的强制类型转换,而是使用标准C的类型转换符:sta…

Java NIO框架Mina、Netty、Grizzly介绍与对比

Java NIO框架Mina、Netty、Grizzly介绍与对比 Mina: Mina(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。当前发行的 Mina 版本2.04支持基于 Ja…

Façade Pattern

目前整理的门面模式 的使用有三种情况。下面分别讨论。 第一种情况 客户类要使用的功能分布在多个类中,这些类可能相互之间没有什么关系;客户在使用后台的时候,必须先初始化要使用到的功能所在的类,然后才能使用。这时候&#xff…

架构、框架、模式、模块、组件、插件、控件、中间件的含义和区别

架构、框架、模式、模块、组件、插件、控件、中间件的含义和区别。经常看到这些概念,但是有些含糊,花点儿功夫整理一下,结果还是有些地方理解的不透彻,先将整理的内容写下来,以供交流。左侧英文栏中有些单词被分成了两…

mina 框架java服务端的搭建和通信

创建java项目,导入mina包。mina下载地址:http://mina.apache.org/ 不会用mina的请各种百度谷歌吧。。 新建MainServer.java类,继承于Thread并实现main函数。 然后就在MainServer类里搭建main结构啦。 类如下: 12345678910…