载器 ClassLoaderA 和 ClassLoaderB 分别读取了这个 Sample.class 文 件,并定义出两个 java.lang.Class 类的实例来表示这个类。这两个实例是不 相同的。对于 Java 虚拟机来说,它们是不同的类。试图对这两个类的对象进行 相互赋值,会抛出运行时异常 ClassCastException。下面通过示例来具体说明 。代码清单 3 中给出了 Java 类 com.example.Sample。
清单 3. com.example.Sample 类
package com.example;
public class Sample {
private Sample instance;
public void setSample(Object instance) {
this.instance = (Sample) instance;
}
}
深入探讨Java类加载器(4)
时间:2011-06-12 IBM 成富
如 代码清单 3 所示,com.example.Sample 类的方法 setSample 接受一个 java.lang.Object 类型的参数,并且会把该参数强制转换成 com.example.Sample 类型。测试 Java 类是否相同的代码如 代码清单 4 所示 。
清单 4. 测试 Java 类是否相同
public void testClassIdentity() {
String classDataRootPath = "C:\\workspace\\Classloader\\classData";
FileSystemClassLoader fscl1 = new FileSystemClassLoader (classDataRootPath);
FileSystemClassLoader fscl2 = new FileSystemClassLoader(classDataRootPath);
String className = "com.example.Sample";
try {
Class<?> class1 = fscl1.loadClass(className);
Object obj1 = class1.newInstance();
Class<?> class2 = fscl2.loadClass(className);
Object obj2 = class2.newInstance();
Method setSampleMethod = class1.getMethod("setSample", java.lang.Object.class);
setSampleMethod.invoke(obj1, obj2);
} catch (Exception e) {
e.printStackTrace();
}
}
代码清单 4 中使用了类 FileSystemClassLoader 的两个不同实例来分别加载类 com.example.Sample,得到了两个不同的 java.lang.Class 的实例,接着通过 newInstance() 方法分别生成了两个类的对象 obj1 和 obj2,最后通过 Java 的反射 API 在对象 obj1 上调用方法 setSample,试图把对象 obj2 赋值给 obj1 内部的 instance 对象。代码清单 4 的运行结果如 代码清单 5 所示。
清单 5. 测试 Java 类是否相同的运行结果
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at classloader.ClassIdentity.testClassIdentity(ClassIdentity.java:26)
at classloader.ClassIdentity.main(ClassIdentity.java:9)
Caused by: java.lang.ClassCastException: com.example.Sample
cannot be cast to com.example.Sample
at com.example.Sample.setSample(Sample.java:7)
... 6 more
从 代码清单 5 给出的运行结果可以看到,运行时抛出了 java.lang.ClassCastException 异常。虽然两个对象 obj1 和 obj2 的类的名 字相同,但是这两个类是由不同的类加载器实例来加载的,因此不被 Java 虚拟 机认为是相同的。
了解了这一点之后,就可以理解代理模式的设计动机 了。代理模式是为了保证 Java 核心库的类型安全。所有 Java 应用都 |