最近看了Java的类加载机制,在此mark一下。
1. 类加载器的种类
Java虚拟机中可以安装多个类加载器,系统默认主要有四个类加载器,每个类负责加载特定位置的类:BootStrapClassLoader,ExtClassLoader,AppClassLoader和URLClassLoader。LI另外程序员可以自定义类加载器,自定义的加载器必须继承ClassLoader。类加载器也是Java类,因为其它Java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这个就是BootStrap。BootStrap它是嵌套在Java虚拟机内核中的,jvm启动,这个类就会启动,它是由c++语言编写的。此外,Java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类加载器对象或者默认采用系统类加载器为其父级类加载。
2. 类加载器的机制
采用父委托机制,即运行一个程序时,总是由AppClassLoader(系统类加载器)开始加载指定的类。在加载类时,每个类加载器会将加载任务上交给其父,如果其父找不到,再由自己去加载。Bootstrap Loader(启动类加载器)是最顶级的类加载器了,其父加载器为null.
父委托机制优点:提供了软件系统的安全性。因为在此机制下,用户自定义的类加载器不可能加载应该由父加载器加载的可靠类。从而防止不可靠的甚至恶意的代码代替父加载器的可靠代码。
详细分析见:http://topmanopensource.iteye.com/blog/667229
3.自定义类加载的过程
(1) 寻找jre目录,寻找jvm.dll,并初始化JVM;
(2) 产生一个BootstrapClassLoader(启动类加载器);
(3) BootstrapClassLoader自动加载Extended Loader(标准扩展类加载器),并将其父Loader设为Bootstrap Loader;
(4) BootstrapClassLoader自动加载AppClass Loader(系统类加载器),并将其父Loader设为Extended Loader;
(5) 最后由AppClassLoader加载自定义类。
4. 类的加载方式
(1) 命令行启动应用时候由JVM初始化加载;
(2) 通过Class.forName()方法动态加载;
(3) 通过ClassLoader.loadClass()方法动态加载。
5. 具体实例
(1) 定义被加载类
public class HelloWorld {
public HelloWorld() {
System.out.println("constructor ... ");
}
}
(2) 定义类加载器
public class CustomerClassLoader extends ClassLoader{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//class文件所在目录
private String path = "D:\\***\\bin\\com\\test\\classloader\\";
public CustomerClassLoader(String name) {
// TODO Auto-generated constructor stub
super();
this.name = name;
}
public CustomerClassLoader(ClassLoader parent, String name) {
// TODO Auto-generated constructor stub
super(parent);
this.name = name;
}
public byte[] loadClassData(String name) {
try {
FileInputStream fin = new FileInputStream(new File(path + name + ".class"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int n = 0;
while ((n = fin.read()) != -1) {
baos.write(n);
}
fin.close();
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
byte [] data = loadClassData(name);
return this.defineClass("com.test.classloader." + name, data, 0, data.length, null);
}
}
(3) 定义测试类
public class JavaInterview_9 {
public static void main(String[] args) {
try {
CustomerClassLoader ccl = new CustomerClassLoader("ccl");
Class<?> clazz = ccl.loadClass("HelloWorld");
clazz.newInstance();
System.out.println(ccl);
System.out.println(ccl.getParent());
System.out.println(ccl.getParent().getParent());
System.out.println(ccl.getParent().getParent().getParent());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
(4) 测试结果
从上面的结果可以看出,并没有获取到ExtClassLoader的父Loader,原因是Bootstrap Loader(启动类加载器)是用C语言实现的,找不到一个确定的返回父Loader的方式,于是就返回null。