1. 创建用户自定义的类加载器:
要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定的类的名字,返回对应的Class对象的引用。
2. 自定义类加载器:
MyClassLoader.java 该例子主要用来验证父类委托机制!
public class MyClassLoader extends ClassLoader {
private String name; // 类加载器的名字
private String path = "d:\\"; // 加载类的路径
private final String fileType = ".class"; // class文件的扩展名
public MyClassLoader(String name) {
super(); // 让系统类加载器成为该类加载器的父加载器
this.name = name;
}
public MyClassLoader(ClassLoader parent, String name) {
super(parent); // 显式指定该类加载器的父加载器
this.name = name;
}
@Override
public String toString() {
return this.name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
// 重写的时候把protected改为public
// 获取字节数组
byte[] data = this.loadClassData(name);
// 将字节数组转换成Class对象返回
return this.defineClass(name, data, 0, data.length);
}
/**
* 得到class文件的二进制字节数组
*
* @param name
* @return
*/
private byte[] loadClassData(String name) {
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = null;
try {
// 将完整类名中的.转化成\
name = name.replace(".", "\\");
is = new FileInputStream(new File(path + name + fileType));
baos = new ByteArrayOutputStream();
int ch = 0;
while (-1 != (ch = is.read())) {
baos.write(ch);
}
data = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
baos.close();
} catch (Exception e2) {
}
}
return data;
}
// main方法用来测试
public static void main(String[] args) throws Exception {
MyClassLoader loader1 = new MyClassLoader("loader1");
// loader1的父加载器是系统类加载器
// 系统类加载器会在classpath指定的目录中加载类
loader1.setPath("d:\\myapp\\serverlib\\");
MyClassLoader loader2 = new MyClassLoader(loader1, "loader2");
// 将loader1作为loader2的父加载器
loader2.setPath("d:\\myapp\\clientlib\\");
MyClassLoader loader3 = new MyClassLoader(null, "loader3");
// loader3的父加载器是根类加载器
loader3.setPath("d:\\myapp\\otherlib\\");
// 测试加载
test(loader2);
test(loader3);
// 测试不同命名空间的类的互相访问
test2(loader3);
}
public static void test(ClassLoader loader) throws Exception {
Class clazz = loader.loadClass("Sample");
Object object = clazz.newInstance();
}
public static void test2(ClassLoader loader) throws Exception {
Class clazz = loader.loadClass("Sample");
Sample object = (Sample) clazz.newInstance();
System.out.println("sample v1: " + object.v1);
}
}
Sample.java
public class Sample {
public int v1 = 1;
public Sample() {
System.out.println("Sample is loaded by: " + this.getClass().getClassLoader());
// 主动使用Dog类
new Dog();
}
}
Dog.java
public class Dog {
public Dog() {
System.out.println("Dog is loaded by: " + this.getClass().getClassLoader());
}
}
test3方法中,MyClassLoader类由系统类加载器加载,而Sample类由loader3类加载器加载,因此MyClassLoader类看不见Sample类。
在MyClassLoader类的main()方法中使用Sample类会导致错误。
当两个不同命名空间内的类互相不可见时,可采用Java反射机制来访问对方实例的属性和方法,即反射可以突破命名空间的限制。