Java ClassLoader详解(二)

2014-11-24 00:38:50 · 作者: · 浏览: 1
时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,依次类推。在介绍代理模式背后的动机之前,首先需要说明一下 Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。比如一个 Java 类 com.example.Sample,编译之后生成了字节代码文件 Sample.class。两个不同的类加载器 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;

  }

  }

  如 代码清单 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 对象。代码清