Java ClassLoader机制及初始化步骤

Java类加载及变量初始化过程

Java虚拟机是如何将编译好的class文件加载成为Java类型?加载之后如何初始化?静态变量、静态代码块的初始化顺序以及继承中子类和父类的初始化顺序?
在学习Java的过程中经常会遇到这种问题,最初baidu、Google一下能搞清顺序,但不明白其内部流程,因而过段时间就会忘记。最近涉及到静态内部类单例模式和普通单例模式的对比,始终想不通类加载和变量初始化的机制,因而查找资料,整理一下。

Java类加载机制

类加载是通过ClassLoader来实现的,由于不同的JVM实现不同,本文仅限于常用的Hotspot JVM实现。

JDK默认的ClassLoader

JDK默认提供了一下三种类加载器:

  1. Bootstrp loader

    Bootstrp加载器是Java虚拟机的引导加载器,在Java虚拟机启动后初始化的,负责加载Java的核心类库,包括%JAVA_HOME%/jre/lib,-Xbootclasspath参数路径以及%JAVA_HOME%/lib/classes中的类库,由C++编写

  2. ExtClassLoader

    由Bootstrp加载,并且其父加载器为Bootstrp,负责加载Java的扩展类库,包括%JAVA_HOME%/jre/lib/ext下的类库,由Java编写,sun.misc.Launcher$ExtClassLoader

  3. AppClassLoader

    由Bootstrp加载,并且其父加载器为ExtClassLoader,负责加载应用以及应用classpath下的类库,是Java应用程序默认的加载器,由Java编写,sun.misc.Launcher$AppClassLoader

双亲委托模型

Java的ClassLoader都采用双亲委托机制,即为每个类加载器都指定一个父加载器,并在当前加载器中保存父加载器的引用。双亲委托机制的主要作用是为了防止类的重复加载,采用双亲委托机制加载类时的步骤如下:

  1. 当前ClassLoader首先从自己已经加载的类中查询是否已经加载了该类,如果已经加载了则直接返回该类。

    每个类加载器都有自己的加载缓存,当一个类被加载之后就会放入缓存,私以为就是PermGen Space

  2. 当前ClassLoader没有找到该类,则委托其父加载器去加载,父加载器采用同样的策略,一直到Bootstrp加载器。

  3. 当所有的父加载器都没有加载时,返回委托加载的源头即最初的加载器,由其根据文件路径去找到相应的jar包进行加载。

那么问题来了,Java虚拟机如何确定两个类是不是同一个类呢。一方面通过类的全限定名,另一方面是通过ClassLoader名。即完全相同的两个class文件,由不同的ClassLoader进行加载,在Java虚拟机中会被认为是两个不同的类,当然由于双亲委托机制的存在,这种情况基本不会存在,不然就会出现在不知情的情况下个人自定义的String代替JDK基本String的情况。

不遵循双亲委托的情景

上面说了双亲委托机制是为了实现不同的ClassLoader之间加载类的交互问题,被大家公用的类就交由父加载器进行加载,但是Java中也确实存在父加载器中需要用到子加载器中加载的类的情况。
Java中有一个SPI(Service Provider Interface)标准,使用了SPI的库,诸如JDBC、JNDI等,我们都知道JDBC需要第三方提供的驱动才可以,而包含驱动的jar放在个人应用的classpath下。JDBC本身的api是JDK提供的一部分,它已经被Bootstrp加载了,那么第三方厂商提供的实现类怎么加载呢?这里Java引入了线程上下文加载的概念,线程类加载器默认从父线程继承,如果没有指定的话就是APPClassLoader,这样的话当加载第三方驱动时就可以通过线程的上下文类加载器来加载。

Java虚拟机加载class文件的过程

虚拟机将class文件加载到内存,通过校验、解析和初始化,最终形成Java类型。加载、校验、准备、解析、初始化这5个步骤的顺序是确定的,但是在Java标准规范中并没有强制规定什么时候开始加载,但是却规定了几种情况必须初始化。

  1. 遇到new、getstatic、putstatic、invokestatic这4条字节码指令,如果类没有进行过初始化,则触发初始化。
  2. 使用Java.lang.reflect包的方法进行反射调用时,如果没有初始化则先进行初始化。
  3. 初始化一个类时如果发现父类没有初始化,则先初始化父类。

加载、校验、解析

加载就是通过类的全限定名,获取类的二进制字节流,然后将此字节流转换为方法去的数据结构,在内存中生成一个代表此类的Class对象的过程。验证 是为了为了确保Class文件中的字节流符合虚拟机的要求,并且不会危害虚拟机的安全。解析是虚拟机将常量池中的符号引用转换为直接引用的过程。class文件采用一种类似C语言的结构体的伪结构来存储我们编码的java类的各种信息。其中,class文件中常量池(constant_pool)是一个类似表格的仓库,里面存储了我们编写的java类的类和接口的全限定名,字段的名称和描述符,方法的名称和描述符。在java虚拟机将class文件加载到虚拟机内存之后,class类文件中的常量池信息以及其他的数据会被保存到java虚拟机内存的方法区。我们知道class文件的常量池存放的是java类的全名,接口的全名和字段名称描述符,方法的名称和描述符等信息,这些数据加载到jvm内存的方法区之后,被称做是符号引用。而把这些类的全限定名,方法描述符等转化为jvm可以直接获取的jvm内存地址,指针等的过程,就是解析。

准备

在Java虚拟机加载了class文件并且验证完毕之后,就会正式给类变量分配内存空间并设置变量的初始值。这些类变量所使用的的内存都会保存在方法区(PermGen Space)中,这里说的类变量也就是通过static修饰的静态变量。比如在public static int value=123;中,在执行准备阶段时会给value分配内存并设置初始值为0,而不是现象中的123.

初始化阶段

类初始化阶段是类加载的最后阶段,在这个阶段才会真正意义上的执行类中定义的Java代码。Java虚拟机是怎样完成初始化的呢?这要从编译讲起。在编译阶段,编译器会自动收集类中的所有静态变量和静态代码块(static{}块)并将其合并,编译器的收集顺序是按照他们在类中的定义顺序。收集完成之后会编译Java类中的static{}方法,Java虚拟机则会保证一个类中的static{}块在多线程或单线程环境下都正确的执行,并且只执行一次。在执行过程中便完成了static变量的初始化。当我们的Java代码中没有显示的声明static代码块,而只是定义了静态变量的话,编译器会默认给我们生成一个static{}方法。

如果出现了继承的情况,虚拟机会保证在子类的static{}代码块执行之前,父类的static已经执行完毕。

参考博客地址

Java类加载及变量初始化过程 https://my.oschina.net/kalo/blog/323078

Java Classloader机制解析 https://my.oschina.net/aminqiao/blog/262601

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

推荐阅读更多精彩内容