类加载流程,类加载机制及自定义类加载器详解(面试再也不怕了) (4)

注意:类加载器之间的父子关系并不是类继承上的父子关系,而是实例之间的父子关系。

类加载流程,类加载机制及自定义类加载器详解(面试再也不怕了)

public class ClassloaderPropTest {
    public static void main(String[] args) throws IOException {
        //获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println("系统类加载器:" + systemClassLoader);
        /*
        获取系统类加载器的加载路径——通常由CLASSPATH环境变量指定,如果操作系统没有指定
        CLASSPATH环境变量,则默认以当前路径作为系统类加载器的加载路径
         */

        Enumeration<URL> eml = systemClassLoader.getResources("");
        while (eml.hasMoreElements()) {
            System.out.println(eml.nextElement());
        }
        //获取系统类加载器的父类加载器,得到扩展类加载器
        ClassLoader extensionLoader = systemClassLoader.getParent();
        System.out.println("系统类的父加载器是扩展类加载器:" + extensionLoader);
        System.out.println("扩展类加载器的加载路径:" + System.getProperty("java.ext.dirs"));
        System.out.println("扩展类加载器的parant:" + extensionLoader.getParent());
    }
}
//输出结果
//系统类加载器:sun.misc.Launcher$AppClassLoader@18b4aac2
//file:/C:/ProjectTest/FengKuang/out/production/FengKuang/
//系统类的父加载器是扩展类加载器:sun.misc.Launcher$ExtClassLoader@1540e19d
//扩展类加载器的加载路径:C:\SorftwareInstall\java\jdk\jre\lib\ext;C:\WINDOWS\Sun\Java\lib\ext
//扩展类加载器的parant:null

从输出中验证了:系统类加载器的父加载器是扩展类加载器。但输出中扩展类加载器的父加载器是null,这是因为父加载器不是java实现的,是C++实现的,所以获取不到。但扩展类加载器的父加载器是根加载器。

1.2、类加载流程

类加载流程,类加载机制及自定义类加载器详解(面试再也不怕了)

图中红色部分,可以是我们自定义实现的类加载器来进行加载。

五、创建并使用自定义类加载器 1、自定义类加载分析

除了根类加载器,所有类加载器都是ClassLoader的子类。所以我们可以通过继承ClassLoader来实现自己的类加载器。

ClassLoader类有两个关键的方法:

protected Class loadClass(String name, boolean resolve):name为类名,resove如果为true,在加载时解析该类。

protected Class findClass(String name) :根据指定类名来查找类。

所以,如果要实现自定义类,可以重写这两个方法来实现。但推荐重写findClass方法,而不是重写loadClass方法,因为loadClass方法内部回调用findClass方法。

我们来看一下loadClass的源码

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            //第一步,先从缓存里查看是否已经加载
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                //第二步,判断父加载器是否为null
                    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) {
                   //第三步,如果前面都没有找到,就会调用findClass方法
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                   sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

loadClass加载方法流程

判断此类是否已经加载;

如果父加载器不为null,则使用父加载器进行加载;反之,使用跟加载器进行加载;

如果前面都没加载成功,则使用findClass方法进行加载。

所以,为了不影响类的加载过程,我们重写findClass方法即可简单方便的实现自定义类加载。

2、实现自定义类加载器

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjjxs.html