其他分享
首页 > 其他分享> > 01 类加载子系统

01 类加载子系统

作者:互联网

类加载子系统

概述

image-20220725103653498

JVM 内存的结构

image-20220725103755006

类加载器子系统的作用

类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开始由特定的文件标识

ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定。

加载的类信息存放于一块称为方法区的内存空间。除了类信息外,方法区中还会存放运行时常量池的信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)

image-20220725104318690

类的加载过程

image-20220725104414140

完整流程图

image-20220725104455098

1.加载

加载class文件的方式

2.链接

初始化

public class ClinitTest {
    static class Father {
        public static int A = 1;

        static {
            A = 2;
        }
    }

    static class Son extends Father {
        public static int B = A;
    }

    public static void main(String[] args) {
        // 加载Father类
        // 加载Son类
        System.out.println(Son.B);
    }
}

输出结果为 2,也就是说首先加载ClinitTest1的时候,会找到main方法,然后执行Son的初始化,但是Son继承了Father,因此还需要执行Father的初始化,同时将A赋值为2。我们通过反编译得到Father的加载过程,首先我们看到原来的值被赋值成1,然后又被复制成2,最后返回

类加载器的分类

image-20220725105542417

这里的四者之间是包含关系,不是上层和下层,也不是子系统的继承关系。

public class ClassLoaderTest {
    public static void main(String[] args) {
        // 获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        // sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(systemClassLoader);
        // 获取其上层:拓展类加载器
        ClassLoader parent = systemClassLoader.getParent();
        // sun.misc.Launcher$ExtClassLoader@1540e19d
        System.out.println(parent);
        // 获取顶层加载器 BootStrapClassLoader 获取不到 因为C/C++写的
        ClassLoader parent1 = parent.getParent();
        // null
        System.out.println(parent1);

        // 对于用户来说 默认使用的是系统类加载器
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        // sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(classLoader);
        // sun.misc.Launcher$ExtClassLoader@1540e19d
        ClassLoader parent2 = classLoader.getParent();
        System.out.println(parent2);
        // 在上层
        // null
        ClassLoader parent3 = parent2.getParent();
        System.out.println(parent3);
        
        // Java的核心类库都是使用引导类加载的
        // String 类是使用引导类加载器加载的
        ClassLoader classLoader1 = String.class.getClassLoader();
        System.out.println(classLoader1);
    }
}

虚拟机自带的加载器

public class ClassLoaderTest1 {
    public static void main(String[] args) {
        System.out.println("启动类加载器");
        URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
        for (URL urL : urLs) {
            System.out.println(urL.toString());
        }

        System.out.println("拓展类加载器");
        String property = System.getProperty("java.ext.dirs");
        for (String path : property.split(";")) {
            System.out.println(path);
        }
    }
}
启动类加载器
file:/D:/jdk/jdk1.8/jre/lib/resources.jar
file:/D:/jdk/jdk1.8/jre/lib/rt.jar
file:/D:/jdk/jdk1.8/jre/lib/sunrsasign.jar
file:/D:/jdk/jdk1.8/jre/lib/jsse.jar
file:/D:/jdk/jdk1.8/jre/lib/jce.jar
file:/D:/jdk/jdk1.8/jre/lib/charsets.jar
file:/D:/jdk/jdk1.8/jre/lib/jfr.jar
file:/D:/jdk/jdk1.8/jre/classes
拓展类加载器
D:\jdk\jdk1.8\jre\lib\ext
C:\WINDOWS\Sun\Java\lib\ext

用户自定义类加载器

在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,来定制类的加载方式。
为什么要自定义类加载器?

用户自定义类加载器实现步骤:

获取ClassLoader的途径

双亲委派机制

Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式。

image-20220725110339764

优势

沙箱安全机制

自定义string类,但是在加载自定义String类的时候会率先使用引导类加载器加载,而引导类加载器在加载的过程中会先加载jdk自带的文件(rt.jar包中java\lang\String.class),报错信息说没有main方法,就是因为加载的是rt.jar包中的string类。这样可以保证对java核心源代码的保护,这就是沙箱安全机制。

其他

类的主动使用和被动使用

标签:01,Java,自定义,ClassLoader,子系统,JVM,class,加载
来源: https://www.cnblogs.com/flypigggg/p/16519009.html