一文入门类加载器

java.lang.class类

Class类的实例表示正在运行的Java应用程序中的类或接口. Class类没有公共构造函数,那他是如何建立的呢? 咱们来看看官方文档是如何说的java

Instead {@code Class} objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the {@code defineClass} method in the class loader.c++

Class对象是由Java虚拟机在加载类时自动构造的,并经过调用类加载器中的defineClass方法来构造. 每一个Class对象包含一个定义他的类加载器的引用.jvm

private final ClassLoader classLoader;函数

下面咱们就来认识一下类加载器.this


什么是类加载器

看看jdk文档怎么说:spa

A class loader is an object that is responsible for loading classes.Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the classdebug

类加载器是负责加载类的对象,给定一个类的全限定名,类加载应该尝试生成包含在类定义里面的数据流 通俗点解释就是: .java文件编译后生成.class文件, 类加载器就是将.class文件转换成java.lang.Class类的一个实例3d


类加载器的分类

启动类加载器(BootstrapClassLoader)

负责加载系统类,由c语言实现,没有对应的类加载器 加载路径: System.getProperty("sun.boot.class.path");code

扩展类加载器(Extension Class Loader)

负责加载扩展类 加载路径 System.getProperty("java.ext.dirs");cdn

应用类加载器(AppClassLoader)

从用户类路径下加载 加载路径 System.getProperty("java.class.path");

验证

System.out.println(String.class.getClassLoader()); // 加载系统类用到的类加载器
System.out.println(Student.class.getClassLoader()); // Student是用户自定义的类
复制代码

输出一下查看结果

null
sun.misc.Launcher$AppClassLoader@18b4aac2
复制代码

由于String是系统类,因此由BootstrapClassLoader加载,而BootstrapClassLoader没有对应的类加载器,因此为null

Student是在用户类路径下定义的,因此是由AppClassLoader加载


双亲委派机制

除了启动类加载器外,全部的类加载器都有一个父类加载器。类加载器要先把加载类的机会交给他的父类加载器在父类加载器加载失败时,他才会加载该类

类加载器层次结构图:

类加载2.png

加载Studeng类的过程: AppClassLoader先交给其父类ExtentsionClassLoader加载,ExtensionClassLoader交给他的父类BootstrapClassLoader加载,BootstrapClassLoader没有父类加载器,尝试加载,加载失败,让其子类ExtensionClassLoader加载,一样加载失败,交给其子类AppClassLoader加载,加载成功!

源码追踪

sun.misc.Launcher类

Launcher类是java应用的入口,由JVM建立的,源码对外隐藏,只能经过反编译查看. 为何Launcher类是java应用的入口? 由于 ApplicationClassLoader和ExtClassLoader都是在Launcher类定义的

双亲委派机制源码

ClassLoader类的loadClass()方法

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        // 加锁机制
        synchronized (getClassLoadingLock(name)) {
            // 给定一个类的全限定名,检查类是否被加载过,底层调用的c++方法,不须要深刻研究
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 先让其父类加载
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        // 父类为空,则让BootStrapClassLoader加载该类
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    
                }

                if (c == null) {
                   
                    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;
        }
    }
复制代码

你们本身都debug几遍,就能搞懂双亲委派机制的流程,我就不贴图了,求关注


关注公众号,免费领取优秀jvm入门书籍

相关文章
相关标签/搜索