zoukankan      html  css  js  c++  java
  • 三层类加载器、双亲委派模型--Java类加载器总结分析

    Java类加载过程总结分析这篇博文中,我们提到,JVM类加载的第一步就是”加载“,而这一步就是由Java的类加载器完成

    类加载器的作用:通过一个类的全限定名来获取描述该类的二进制字节流

    注意:对于任意一个类,都必须由它的类加载器和这个类本身一起确立其在JVM中的唯一性,即 :即使两个类来源同一Class文件,被同一个JVM加载,但只要加载他们的类加载器不同,这两个类就不相等!

    package Q2;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class ClassLoaderTest {
        public static void main(String[] args) throws Exception {
            ClassLoader myLoader = new ClassLoader() {
                @Override
                public Class<?> loadClass(String name) throws ClassNotFoundException {
                    try {
                        String fileName = name.substring(name.indexOf(".") + 1)+".class";
                        InputStream is = getClass().getResourceAsStream(fileName);
                        if (is == null) {
                            return super.loadClass(name);
                        }
                        byte[] b = new byte[is.available()];
                        is.read(b);
                        return defineClass(name,b,0,b.length);
                    } catch (IOException e) {
                        throw new ClassNotFoundException(name);
                    }
                }
            };
    
            Object obj = myLoader.loadClass("Q2.ClassLoaderTest").newInstance();
    
            System.out.println(obj.getClass());
            System.out.println(obj instanceof Q2.ClassLoaderTest);
        }
    }

    输出结果为

    class Q2.ClassLoaderTest
    false

    以上程序构造了一个简易的类加载器,用这个类加载器去加载测试类,根据结果显示,obj对象的确是Q2.ClassLoaderTest的实例,但是类型检查却返回false,

    这是因为虚拟机中同时存在了两个ClassLoaderTest类,一个由虚拟机的应用程序类加载器加载,一个由自定义类加载器加载,虽然来自同一Class文件,但仍属于两相互独立的类,在对象所属对象类型检查时即返回false。

    三层类加载器

      Java中存在以下三类类加载器

        1. 启动类加载器(Bootstrap ClassLoader):这个类加载器负责加载存放在<JAVA_HOME>lib目录,或者被-Xbootclasspath参数指定的路径中存放的,且是JVM能够识别的类库。只有这个类加载器是使用C++语言实现,是JVM的一部分,其他类加载器全部由java语言实现,独立存在于JVM外部,且都继承于java.lang.Classloader抽象类。

        2. 扩展类加载器(Extension ClassLoader):负责加载<JAVA_HOME>homeext目录中,或者被java.ext.dirs系统变量所指定的路径中所有的类库,开发者可以直接使用此类加载器加载Class文件。

        3. 应用程序类加载器(Application ClassLoader):负责加载用户类路径(ClassPath)上的所有类库,开发者同样可以直接使用此类加载器,如果没有指定,则默认使用此类加载器。

      三层类加载器、双亲委派模型

                                           

      JDK9之前,Java应用都由这三种类加载器相互配合完成,如果由必要,用户可以自定义类加载器进行拓展。

      如图所示, 除了最顶层的启动类加载器外,其余的加载器都必须有父类加载器,只不过这里一般使用组合关系来复用父类的代码。

      双亲委派模型工作过程

        如果一个类加载器收到了类加载请求,它自身不会第一时间去尝试加载这个类,而是把这个请求委派给自己的父类加载器去执行,因此所有的加载请求最终都会传输到最顶层的启动类加载器,只有父类加载器反馈自己无法完成加载时(搜索范围内没有找到需要的类),子类加载器才会去尝试自己完成加载。

      双亲委派模型的好处

        可以保证无论哪一个类加载器要要加载类C,都可以保证类的唯一性。如无论那个类加载器要加载Object类,最终都会轮到启动类加载器去加载Object类。反之,如果没有双亲委派的话,由各个类自行加载,那么就可能出现多个不同的类C,导致程序混乱。

      双亲委派模型的源码分析:

    protected synchronized Class<?> loadClass(String name,boolean resolve)
                throws ClassNotFoundException {
            //首先检查请求的类是否已经加载过
            Class c = findLoadedClass(name);
            if (c == null) {
                try {
                    if (parent != null) {
                         c = parent.loadClass(name,false);  //父类加载器不为空,调用父类加载器
                    }else {
                        c = findBootstrapClassOrNull(name); //父类加载器为空,则使用启动类加载器
                    }
                }catch (ClassNotFoundException e) {
                    //如果父类加载器抛出ClassNotFoundException
                    //说明父类无法完成加载请求
                }
                if (c == null) {
                    //在父类无法加载时,调用本身类加载器进行加载
                    c = findClass(name);
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }

      注意:

         在JDK9以后,Java类库实行模块化,不同的类库组成不同的模块,类加载系统也随之发生了一些变化,比如:扩展类加载器被平台类加载器替代等

                       

      如上图所示,JDK9及以后虽然维持着三层类加载器和双亲委派的架构,但类加载的委派关系发生了变动

      当平台及应用程序类加载器收到类加载请求,在委派给父类加载器之前,会判断该类能否归属到某一个系统模块中,如果可以找到归属关系,就优先委派给负责加载那个模块的加载器进行加载!

  • 相关阅读:
    (转载)C++ string中find() ,rfind() 等函数 用法总结及示例
    UVA 230 Borrowers (STL 行读入的处理 重载小于号)
    UVA 12100 打印队列(STL deque)
    uva 12096 The SetStack Computer(STL set的各种库函数 交集 并集 插入迭代器)
    uva 1592 Database (STL)
    HDU 1087 Super Jumping! Jumping! Jumping!
    hdu 1176 免费馅饼
    HDU 1003 Max Sum
    转战HDU
    hust 1227 Join Together
  • 原文地址:https://www.cnblogs.com/dwwzone/p/12851876.html
Copyright © 2011-2022 走看看