java文件要运行,除了需要编程成字节码文件class文件
还要有类加载器去加载class文件。
判断两个类是否一样?
在同一个虚拟机的前提下
- 两个类包名是否一样(类名称空间)。
- 加载这两个类的类加载器是否一样。
类加载分为两种:
- 一种是启动类加载器(Bootstrap ClassLoader),这个类加载器是使用C++语言实现的,是虚拟机自身的一部分。
- 另一种是是其他所有的类加载器。这部分是java语言实现的,独立与虚拟机之外的。
所为开发者的角度,其加载器可以细分为:
- 启动类加载器 bootstrap
加载jdk的lib目录下的所有类 - 拓展类加载器 extention
加载jdk目录下ext文件夹下的所有类 - 应用程序类加载器 application
这个是程序默认的类加载器,加载jvm启动时,ClassPath上指定的所有类。 - 自定义类加载器
这个是开发者自己实现的类加载器
类在加载过程按照双亲委派模型,这并不是严格要求约束的。是默认的实现方式,这种方式带来的好处,就是不会导致类加载的混乱。
双亲委派模型的加载过程如下:
如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。
默认的类加载器是Application ClassLoader,会首先看父类加载器是否已经加载了该类,当BootStrap ClassLoader也加载不了时,就是自己去加载。
如何实现自定义类加载器。
ClassLoader类默认的loadClass方法已经帮我们写好了,我们无需去写。看下源码loadClass方法已经实现了双亲委派模型。
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 1.首先,检查这个类是否已经被加载
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// 2.没有被加载,就先委派给父类加载器去加载
// 父加载器为空的话,找到顶层的bootStrap类加载器
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// 3.如果父类加载器依然没法加载类,调起findClass方法,去自己加载
long t1 = System.nanoTime();
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
在细看下双亲委派类加载的过程,看在哪里器实现自定义类加载器。
- 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。
- 如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用parent.loadClass(name, false);).或者是调用bootstrap类加载器来加载。
- 如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载。
所以要实现自定义类加载器,就是要复写findClass方法,在findClass方法里,去用自定义的类加载器加载。
mark等到需要使用时,补充,细了解。
参考:《深入理解java虚拟机》周志明
博文:http://www.importnew.com/24036.html