JVM学习整理——类加载器(ClassLoader)详解

类加载器概述

Java类加载器是JVM的一部分,它主要负责动态的将Java类加载到Java虚拟机的内存当中。

类加载器加载过程

类加载器加载过程主要分为三个阶段,分别是加载阶段,链接阶段,初始化阶段。其中链接阶段也分为三个步骤,分别是验证,准备,解析。(这边参考较多,当笔记先看吧~)在这里插入图片描述

  • 加载
    首先通过类的全限定名称获取此类的一个二进制的字节流。然后会在内存中生成一个java.lang.Class对象,作为方法区这个类各个数据的访问入口。
  • 链接
    链接分为三个阶段。
    验证
    主要用于确保Class文件的字节流中包含信息符合当前虚拟机的要求,保证被加载类的正确性。主要有四种验证:文件格式验证,元数据验证,字节码验证,符号引用验证。
    准备
    为类变量(即static修饰的字段变量)分配内存并且设置该类变量的初始值即0(如static int i=5;这里只将i初始化为0,至于5的值将在初始化时赋值),这里不包含用final修饰的static,因为final在编译的时候就会分配了,注意这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
    解析
    主要将常量池中的符号引用替换为直接引用的过程。符号引用就是一组符号来描述目标,可以是任何字面量,而直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。有类或接口的解析,字段解析,类方法解析,接口方法解析(这里涉及到字节码变量的引用,如需更详细了解,可参考《深入Java虚拟机》)。
  • 初始化
    类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量(如前面只初始化了默认值的static变量将会在这个阶段赋值,成员变量也将被初始化)。

类加载器分类

类加载器主要分为两类,一类是引导类加载器(BoostrapClassLoader),还有一类是自定义类加载器(User-defined ClassLoader),这边注意一下,只要是派生于抽象类ClassLoader的类加载器都属于自定义的类加载器的范围。下图所示是我们使用的三个最常见的类加载器,也进行了整理。
在这里插入图片描述

引导类加载器

  • 引导类加载器(BoostrapClassLoader)主要由c/c++实现,嵌套在JVM内部。
  • 主要用于加载JVM的核心类库,比如JAVA_HOME/jre/lib/rt.jar、resources.jar等等。
  • 引导类加载器没有父类的加载器,它是拓展类以及系统类加载器的父类。
  • 为了安全起见,它知会加载指定包名开头的一些类,比如java,javax等等。

拓展类加载器

  • 由Java编写,使用的是sun.misc.Launcher$ExtClassLoader。派生于ClassLoader。
  • 父类加载器是引导类加载器。
  • 从java.ext.dirs的系统属性的指定目录去加载类库,或者JAVA_HOME/jre/lib/ext子目录去加载类库。这边要注意的是,如果用户的类也放在这些目录下面,同样会被加载。

系统类加载器

  • 由Java编写,使用的是sun.misc.Launcher$AppClassLoader。派生于ClassLoader抽象类。
  • 父类的加载器是拓展类加载器。
  • 主要负责加载classpath或者系统变量java.class.path下指定的类库。
  • 它是默认的类加载器,一般Java应用程序都是通过系统类加载器来加载的。
  • 可以通过ClassLoader.getSystemClassLoader()获得。

下面用代码简单演示一下类的加载器。
这边是简单的获取各个类加载器的一些代码,根据运行结果可以看到相对应的类加载器的结构关系。

    @Test
    public void testGetClassLoader() {
        // 获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
        // 通过classloader.getParent()方法获取系统类加载器的父类加载器,拓展类加载器
        ClassLoader extClassLoader = systemClassLoader.getParent();
        System.out.println(extClassLoader);
        // 获取拓展类系统加载器,启动类加载器,注意启动类加载器输出为null
        ClassLoader bootstrapClassLoader = extClassLoader.getParent();
        System.out.println(bootstrapClassLoader);
    }

 	@Test
    public void testClassLoader2() {
        // 启动类加载器 输出所有加载的jar信息
        System.out.println("--------启动类加载器-----------");
        URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
        for (URL url:urLs) {
            System.out.println(url.toExternalForm());
        }

        // String类是rt.jar下面的一个类,它的classloader是引导类加载器
        ClassLoader classLoader = String.class.getClassLoader();
        System.out.println(classLoader);

        System.out.println("--------拓展类加载器-----------");
        // 扩展类加载器 输出加载的目录信息
        String property = System.getProperty("java.ext.dirs");
        String[] split = property.split(":");
        for (String s:split) {
            System.out.println(s);
        }
        // AWTEventMonitor是拓展类加载的一个类,可以看到它的类加载器是ExtClassLoader
        ClassLoader classLoader1 = AWTEventMonitor.class.getClassLoader();
        System.out.println(classLoader1);

        System.out.println("--------系统类加载器-----------");
        ClassLoader classLoader2 = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader2);
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        // 这边获得的类加载器是一样的,都是系统类加载器
        System.out.println(systemClassLoader);
    }

testGetClassLoader运行结果在这里插入图片描述
testClassLoader2运行结果在这里插入图片描述

双亲委派机制

最后说一下双亲委派机制,其实这个机制也很简单,下面简单整理一下。

  • 首先,类加载器在收到加载类的请求的时候并不会立即去加载这个类,而是一层一层向上委托,交由其父类加载器去执行。
  • 如果父类的加载器还存在父类加载器,就会继续向上委托,直到没有父类加载器了,也就是到了引导类加载器。
  • 之后再由顶向下开始去加载这个类。如果父类加载器可以完成对此类的加载,那么就加载类,返回结束,如果不能的话,再往下去找子类加载器去加载类,依次类推。最终完成类的加载,这个就是双亲委派机制。

双亲委派机制图示在这里插入图片描述

结语以及参考

这边JVM的类加载器的整理就先这样了,这个当做自己学习的一个汇总整理吧,后续还会继续进行JVM知识点的梳理。
博客的代码都在我个人的代码仓上面,代码仓地址:https://github.com/yzh19961031/blogDemo/tree/master/jvm
然后这边参考的是尚硅谷JVM全套教程(宋红康详解java虚拟机),B站地址:https://www.bilibili.com/video/BV1PJ411n7xZ?p=35

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值