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

所属文集: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的类信息后,还可以对其进行操作.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 ClassLoader翻译过来就是类加载器,普...
    尼尔君阅读 652评论 1 0
  • 1、classLoader 类加载器,将class文件加载到JVM虚拟机内存中,使得程序可以运行。通常情况下,JV...
    helloWorld_1118阅读 2,197评论 0 2
  • 转发:本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 ClassLoader翻译过来就是类加载...
    尼尔君阅读 527评论 0 1
  • 一:ClassLoader 从JVM结构图中可以看到,类加载器的作用是将Java类文件加载到Java虚拟机。 只有...
    阿菜的博客阅读 1,775评论 0 8
  • ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于某些框架开发者来说却非常常见...
    时待吾阅读 1,058评论 0 1