ClassLoader学习和总结
Java程序不是一个可执行程序,而是由许多独立的类文件组成的,每一个文件对应一个java类,并且运行时这些类文件不是全部装入内存的,而是根据程序得需要逐渐载入,ClassLoader就是类加载器,作用是将.class文件装载到jvm中。ClassLoader是JVM实现得一部分,当虚拟机运行时加载java核心得API。
一.java类的装载方式
1.隐式装载:程序运行过程中遇到new方式生成的对象时,隐式调用类装载器加载对应的类到jvm中
2.显示装载:通过class.forname()方法,显示装载需要的类
二.类装载器分类介绍
1.Bootstrap ClassLoader:最顶层的加载类,主要加载核心类库
%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等;
2.Extention ClassLoader:扩展的类加载器,主要加载%JRE_HOME%\lib\ext下的jar包和class文件;
3.Appclass Loader:也称为SystemAppClass,加载当前应用的classpath的所有类;
BootStrap loader加载完ExtClassLoader后就会加载AppClassLoader,并且将AppClassLoader的父类加载器指定为
ExtClassLoader
三.测试代码
public class ClassLoaderTest{
public static void main(String args[]){
System.out.println(ClassLoaderTest.class.getClassLoader());
ClassLoader load = ClassLoaderTest.class.getClassLoader();
ClassLoader load1 = load.getParent();
System.out.println(load1);
ClassLoader load2 = load1.getParent();
System.out.println(load2);
}
}
输出:
[email protected]
[email protected]
null
说明了ClassLoaderTest是通过AppClassLoader加载的,AppClassLoader的父加载器是ExtClassLoader
但是ExtClassLoader的父加载器是空的是因为BootstrapLoader是由C++写的,在java的观点上,逻辑上并不存在BootstrapLoader的类实体,所以输出内容为null;
四.双亲委托
JVM加载一个class的时候会先查看这个类是否加载过,如果没有加载过则通过父加载器,然后递归下去知道BootstrapLoader如果Bootstraploader找到了就直接返回,如果没有找到则一级一级的返回,最后到达自身取查找这些对象,这种机制叫做双亲委托。
使用这种机制的好处是可以避免重复加载,如果父加载器已经加载了该类的时候就没有必要子加载器重新加载
另一方面也考虑到了安全因素,如果不使用委托模式,就可以随时使用定义的String来动态代替java核心api中定义的类,这样存在非常大的安全隐患,父类委托方式可以避免这种情况,因为String已经在启动时被加载,所以用户自定义类是无法加载一个自定义的ClassLoader。
protected synchronized Class loadClass(String name ,boolean reslove)
throws ClassNotFoundException
{
//首先检查该name制定的class是否有被加载
Class c = findLoadedClass(name);
if(c == null){
try{
if(parent != null){
//如果parent不为null,则调用parent的loadClass进行加载
c = parent.loadClass(name,false);
}else{
//parent为null则调用BootstarpClassLoader进行加载
c = findBootstrapClass0(name);
}
}catch(ClassNotFoundException e){
//如果仍无法加载成功,则调用自身的findClass进行加载
c = findClass(name);
}
}
if(resolve){
resloeClass(c);
}
return c;
}
五.一些重要的方法
1.loadClass方法
ClassLoader.loadClass()是ClassLoader的入口点,定义如下:
calss loadClass(String name,boolean reslove)
name是指JVM需要的类的名称,如java.lang.Object,relove参数告诉方法是否需要解析类,在准备执行类之前,需要考虑类解析,(如果JVM找到该类的超类则不需要解析)
2.defineClass方法
defineClass方法接受由原始字节组成的数组,并把它转换成class对象,原始数组包含如从文件按系统或网络装入的数据,defineClass管理JVM的许多复杂的实现层面,因为defineClass方法被标记成final的所以不能覆盖它
3.findSystemClass方法
findSystemClass方法从本地文件系统装入文件,他在本地文件系统中寻找类文件,如果存在,就使用defineClass原始字节转换成Class对象,以将该文件转换成类,
4.resolveClass方法
自己编写loadClass的时候可以调用resolveClass
5.findLoadedClass方法
findLoadedClass充当一个缓存:当请求loadClass装入类时,它调用该方法来查看ClassLoader是否已经装入这个类,这样可以避免重新装入已经存在的类造成麻烦
6.findClass方法
loadClass默认实现调用这个新方法,findClass的用途包含ClassLoader的所有特殊代码,而无需复制其他代码
7.forName方法
class类中有一个静态方法forName,这个方法和ClassLoader中的LoadClass方法目的一样 都是用来加载class的
参考文章:https://www.jianshu.com/p/1f5baa2947d2
参考书:《JAVA程序员面试宝典》