JVM之Java类加载器

前言

通过对Java类加载机制的了解,可以知道大概流程和各自的功能。其中类加载部分的功能是把类的Class文件读入内存,并创建java.lang.Class对象。这部分功能是由类加载器完成的。

1.类加载器分类

①启动类加载器

由C++实现(针对HotSpot),负责将存放在 \lib目录下或Xbootclasspath参数指定的路径中的类库加载到内存中,负责加载Java的核心类。

②其他类加载器

由Java实现,继承自抽象类ClassLoader,分为3种:
a.扩展类加载器:负责加载 \lib\ext目录或java.ext.dirs系统变量指定的路径中的所有类库,即负责加载除Java扩展的核心类之外的类
b.应用程序类加载器:负责加载用户类路径上的指定类库,可直接使用此类加载器,通过ClassLoader.getSystemClassLoader()直接获取。一般情况下,若未自定义类加载器,就默认使用此类加载器

2.双亲委派模型

工作流程:当一个类加载器收到类加载请求,并不会自己立即去加载这个类,而是把请求委托给父加载器去完成,依次往上。所以,所有的类加载请求都是被传递到顶层的启动类加载器中。只有当父加载器中没有搜索到所需的类,即代表无法完成加载时,子加载器才会尝试去加载该类
JVM之Java类加载器_第1张图片
这样的好处在于不同层次的类加载器具有不同的优先级,如所有Java对象的超级父类java.lang.Object位于rt.jar,不管哪个类加载器加载该类,最终都是由启动类加载器加载,保证安全。即使用户自己编写一个java.lang.Object类放上去,虽能正常编译,但是不会被加载运行,保证不会出现混乱

3.双亲委派模型的代码实现

ClassLoader中的loadClass方法实现了双亲委派模型:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
            // 首先,检查该类是否已经加载过
            Class<?> c = findLoadedClass(name);
            if (c == null) {
            //如果该类没有加载,就进入此分支
                try {
                	//父类的加载器不为空,就通过父类的loadClass来加载该类
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                    //否则父类加载器为空,调用启动类加载器加载该类
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // 非空父类的类加载器无法找到对应的类,抛出异常
                }

                if (c == null) {
                    // 如果父类加载器无法加载,就调用findClass方法加载
                    c = findClass(name);//用户可重写该方法,定义类加载器
                }
            }
            return c;
    }

大致流程为:
①检查指定名称的类是否已加载,若加载过,就直接返回
②类尚未加载过,判断是否有父加载器。如果有父加载器,就调用parent.loadClass;否则,就调用bootstrap类加载器加载
③如果父加载器和bootstrap都找不到指定的类,就调用当前类加载器的findClass(可被重写,自定义)方法来完成类加载

你可能感兴趣的:(Java虚拟机)