美文网首页
定义类加载器、初始类加载器

定义类加载器、初始类加载器

作者: rock_fish | 来源:发表于2019-10-27 21:25 被阅读0次

所属文集:ClassLoader串烧


发起一个类的加载过程的类加载器和最终实际加载这个类的类加载器可能并不是一个。前者称为初始类加载器,而后者称为定义类加载器。两者的关联在于:一个 Java 类的定义类加载器是该类所导入的其它 Java 类的初始类加载器。比如类 A 通过 import 导入了类 B,那么由类 A 的定义类加载器负责启动类 B 的加载过程。
比如Person类中用到了String类型的字段。

AppClassLoader 是Person类的定义类加载器
是String的初始类加载器(委托bootStrapClassLoader去加载String类型)
下图中同时带有命名空间的知识,命名空相关的知识可以晚点通过ClassLoader串烧
类加载器的命名空间 实例验证这两个文章去理解。

image.png

当然这个例子有问题,String类是JVM预加载的,可以把String类换成别的非预加载的,但是需要启动类加载器加载的类,如下文中提到的StrictMath。

测试验证,什么初始类加载器
VM参数中加上 : -XX:+TraceClassLoading
日志中可看到类的加载信息

1. 验证通过import 的方式做初始类加载器
  • 验证逻辑:
    1.1 AppClassLoader加载ClassDemo类,ClassDemo类中的方法使用了(import)了需要BootStrap加载的StrictMath的类.
    1.2. new ClassDemo的实例并调用其方法,触发两个类的加载
    1.3 调用AppClassLoader的loadClass方法,查看其findLoadedClass是否返回类信息,若返回了说明AppClassLoader是StrictMath的初始类
    1.4 调用ExtClassLoader的loadClass方法,查看其findLoadedClass是否返回类信息,若没有返回了说明ExtClassLoader不是StrictMath的初始类

  • 实际结论:
    Bootstrap ClassLoader 是StrictMath 的定义类加载器
    AppClassLoader 是 StrictMath 的初始类加载器
    ExtClassLoader 不是 StrictMath 的初始类加载器

  • 验证过程:

public class ClassDemo {
    public int getMath() {
        return  StrictMath.abs(10);
    }
}

@Test
    public void testInitialCL1(){

        try {
            System.out.println("start");
            ClassDemo classDemo = new ClassDemo();
            System.out.println("ClassDemo classLoader :" + ClassDemo.class.getClassLoader());
            classDemo.getMath();//此方法会触发StrictMath类的加载
            System.out.println("------");
            System.out.println(StrictMath.class.getClassLoader());
            Class<?> strictMathClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.StrictMath");
            System.out.println(strictMathClass.getClassLoader());

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

从日志中可以看出
ClassDemo 的类加载器是 AppClassLoader
classDemo.getMath(); 方法中使用了 StrictMath类,
触发了 StrictMath 类的加载;

start
ClassDemo classLoader :sun.misc.Launcher$AppClassLoader@18b4aac2
[Loaded java.lang.StrictMath from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]
------
null
null
[Loaded org.junit.runner.notification.RunNotifier$7 from file:/C:/Users/rock/.m2/repository/junit/junit/4.12/junit-4.12.jar]
[Loaded org.junit.runner.notification.RunNotifier$2 from file:/C:/Users/rock/.m2/repository/junit/junit/4.12/junit-4.12.jar]
[Loaded java.lang.Shutdown from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]

通过 AppClassLoader的 findLoadedClass 成功返回了StrictMath类

image.png

ExtClassLoader的 findLoadedClass 返回了null,不是StrictMath的初始类.


image.png
2. 通过ClassLoader#loadClass()加载类,发起加载的ClassLoader不是初始类加载器
@Test
    public void testInitialCL(){
        //查看GenericSignatureFormatError的初始类加载器
        Class<?> StrictMath  = null;
        try {
            System.out.println("start");
            StrictMath = ClassLoader.getSystemClassLoader().loadClass("java.lang.StrictMath");
            System.out.println(StrictMath.getClassLoader());
            StrictMath = ClassLoader.getSystemClassLoader().loadClass("java.lang.StrictMath");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

从日志上可以看出
第一次loadClass,JVM执行了StrictMath 类的加载动作
且是有bootstrap classloader进行的加载。StrictMath.getClassLoader() = null;


start
[Loaded java.lang.StrictMath from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]
null
[Loaded java.security.Policy from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]
[Loaded java.security.Policy$UnsupportedEmptyCollection from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]
[Loaded java.util.concurrent.atomic.AtomicReference from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]
[Loaded java.security.Policy$PolicyInfo from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]

第二次loadClass, 观察断点信息,AppClassLoader 的findLoadedClass 返回的是null,

image.png

ExtClassLoader 的indLoadedClass 返回的是null,


image.png

bootStrapClassLoader 返回的不是null

image.png

证明了通过loadClass方式发起类加载的动作的classloader,不是初始类加载器

先loadClass 再Import是什么效果呢?
/**
     * StrictMath 是boostrap类加载器加载的。
     * loadClass的方式,AppClassLoader不是其初始类
     * trictMath 是boostrap类加载器加载的。
     * import的方式再使用,AppClassLoader是其初始类
     */
    @Test
    public void testInitialCL2(){
        Class<?> StrictMath  = null;
        try {
            System.out.println("start");
            StrictMath = ClassLoader.getSystemClassLoader().loadClass("java.lang.StrictMath");
            System.out.println(StrictMath.getClassLoader());
            StrictMath = ClassLoader.getSystemClassLoader().loadClass("java.lang.StrictMath");

            System.out.println("start2");
            ClassDemo classDemo = new ClassDemo();
            System.out.println("ClassDemo classLoader :" + ClassDemo.class.getClassLoader());
            classDemo.getMath();//此方法会触发StrictMath类的加载
            System.out.println("------");
            System.out.println(StrictMath.class.getClassLoader());
            Class<?> strictMathClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.StrictMath");
            System.out.println(strictMathClass.getClassLoader());

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
image.png

结论

一个 Java 类的定义类加载器是该类所导入的其它 Java 类的初始类加载器
不同namespace的类是不可见的;除非显示地提供了允许它们进行交互的机制,如得到类所对应的Class对象的引用,使用反射来操作类. 案例1中已证明AppClassLoader不是初始类,其命名空间中没有StrictMath类,但是从bootstrap ClassLoader中拿到了StrictMath的类信息后,还可以对其进行操作.

相关文章

  • ClassLoad

    类的加载过程:类的加载—>类的连接—>类的初始化 类加载器ClassLoader JVM 定义了两种类型的类加载器...

  • 如何理解不同类加载器加载的类不可以互相调用

    不同类加载器加载的类不可以互相调用 专业术语:定义类加载器、初始类加载器 在java中加载器分为4种: 1、app...

  • 定义类加载器、初始类加载器

    所属文集:ClassLoader串烧 发起一个类的加载过程的类加载器和最终实际加载这个类的类加载器可能并不是一个。...

  • 《深入理解JVM虚拟机》读书笔记-类加载器&Java模块化系统

    类加载器 一.类加载器 1.1 类与类加载器 类加载器的定义: Java虚拟机设计团队有意把 类加载阶段中 的“ ...

  • 反射

    类加载器:加载过程 加载,连接,初始化 分类: Bootstrap ClassLoader 根类加载器:核心类的加...

  • 类加载阅读目录

    什么是类加载器 类加载器与类的”相同“判断 类加载器种类 双亲委派模型 类加载过程 自定义类加载器 JAVA热部署...

  • JVM(四)-类加载器

    类加载器大的分类分为两类(JAVA虚拟机规范):引导类加载器、自定义类加载器 引导类加载器(启动类加载器) Boo...

  • java 类加载器

    自定义类加载器 自定义类加载器运行

  • JVM - ClassLoader

    1. 概述 类加载器实际定义了类的namespace。 2.类加载方式之当前类加载器和指定类加载器 类的加载只有两...

  • JVM类加载入门

    一 类加载顺序 class类加载-->验证-->准备--->解析--->初始化 class类加载:通过类加载器加载...

网友评论

      本文标题:定义类加载器、初始类加载器

      本文链接:https://www.haomeiwen.com/subject/pzumvctx.html