类加载之双亲委派模型

java文件要运行,除了需要编程成字节码文件class文件
还要有类加载器去加载class文件。

判断两个类是否一样?
在同一个虚拟机的前提下

  1. 两个类包名是否一样(类名称空间)。
  2. 加载这两个类的类加载器是否一样。

类加载分为两种:

  • 一种是启动类加载器(Bootstrap ClassLoader),这个类加载器是使用C++语言实现的,是虚拟机自身的一部分。
  • 另一种是是其他所有的类加载器。这部分是java语言实现的,独立与虚拟机之外的。

所为开发者的角度,其加载器可以细分为:

  1. 启动类加载器 bootstrap
    加载jdk的lib目录下的所有类
  2. 拓展类加载器 extention
    加载jdk目录下ext文件夹下的所有类
  3. 应用程序类加载器 application
    这个是程序默认的类加载器,加载jvm启动时,ClassPath上指定的所有类。
  4. 自定义类加载器
    这个是开发者自己实现的类加载器

类在加载过程按照双亲委派模型,这并不是严格要求约束的。是默认的实现方式,这种方式带来的好处,就是不会导致类加载的混乱。

双亲委派模型的加载过程如下:


双亲委派过程

如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即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;
        }
    }

在细看下双亲委派类加载的过程,看在哪里器实现自定义类加载器。

  1. 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。
  2. 如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用parent.loadClass(name, false);).或者是调用bootstrap类加载器来加载。
  3. 如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载。
    所以要实现自定义类加载器,就是要复写findClass方法,在findClass方法里,去用自定义的类加载器加载。
    mark等到需要使用时,补充,细了解。

参考:《深入理解java虚拟机》周志明
博文:http://www.importnew.com/24036.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容