Java虚拟机类加载器
类加载器虚拟机设计团队把类加载阶段中的获取二进制字节流这个动作放到Java虚拟机外部去实现,一遍让程序自己决定如何去获取所需要的类,实现这个动作的代码块被称为“类加载器”。同一个Class文件如果被不同的类加载器所加载,那么加载出来的两个类是不相等的,所以某个Class文件只能由一个加载器加载。这边的相等是Class兑现的equals()方法,isInstance()方法,isAssigna...
·
类加载器
虚拟机设计团队把类加载阶段中的获取二进制字节流这个动作放到Java虚拟机外部去实现,一遍让程序自己决定如何去获取所需要的类,实现这个动作的代码块被称为“类加载器”。
同一个Class文件如果被不同的类加载器所加载,那么加载出来的两个类是不相等的,所以某个Class文件只能由一个加载器加载。
这边的相等是Class兑现的equals()方法,isInstance()方法,isAssignableFrom()方法返回的结果。
import java.io.IOException;
import java.io.InputStream;
public class ClassLoaderTest {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
ClassLoader myLoader = new ClassLoader() {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
try {
String className = name.substring(name.lastIndexOf(".") + 1) + ".class";
//返回读取指定资源的输入流
InputStream is = getClass().getResourceAsStream(className);
if (is == null) return super.loadClass(name);
byte[] b = new byte[is.available()];
is.read(b);
//将一个byte数组转换为Class类的实例
return defineClass(name, b, 0, b.length);
} catch (IOException e) {
throw new ClassNotFoundException(name);
}
}
};
Object object = myLoader.loadClass("ClassLoaderTest").newInstance();
System.out.println(object.getClass());
System.out.println(object instanceof ClassLoaderTest);
}
}
以上代码运行结果如下图所示:
可以看到不同加载器说加载的类结果instanceof为false。
双亲委派模型
下面是双亲委派模型的实现,很明显可以看出,为了防止上面的不同类加载器加载同一个class文件的问题,双亲委派模型在加载Class文件的时候先问问其父类加载器有没有加载,所以,最先开始的是:
- 启动类加载器(Bootstrap ClassLoader)这个加载器负责将存放在JAVA_HOME\bin目录下的包,或者被-Xbootclasspath参数所指定的路径中,并且是虚拟机识别的(即使是自己的包放到这个目录下,是不会被加载的)
- 扩展类加载器(Extension ClassLoader):这个加载器负责JAVA_HOME\bin\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。
- 应用程序类加载器(Application ClassLosder):这个加载器负责加载ClassPath上所指定的类库,
先检查是否被加载过,若没有加载则调用父类加载器的loadClass()方法,若父类加载器为空则默认使用启动类加载器作为父类加载器,如果父类加载器加载失败,抛出ClassNotFoundException异常后,再调用自己的findClass()方法进行加载。
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
//1 首先检查类是否被加载
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
//2 没有则调用父类加载器的loadClass()方法;
c = parent.loadClass(name, false);
} else {
//3 若父类加载器为空,则默认使用启动类加载器作为父加载器;
c = findBootstrapClass0(name);
}
} catch (ClassNotFoundException e) {
//4 若父类加载失败,抛出ClassNotFoundException 异常后
c = findClass(name);
}
}
if (resolve) {
//5 再调用自己的findClass() 方法。
resolveClass(c);
}
return c;
}
更多推荐
已为社区贡献7条内容
所有评论(0)