Java虚拟机之Java类的加载

   Java 虚拟机中的类加载,按先后顺序需要经过加载、链接以及初始化三大步骤。
其中,链接过程中同样需要验证;而内存中的类没有经过初始化,同样不能使用。那么,是否所有的 Java 类都需要经过这几步呢
在Java语言中,类型可以分为两大类:基本类型与引用类型。其中基本类型都是有Jav虚拟机预先定义好的。而引用类型又可以细分成四种:类,接口,数组类和泛型参数。由于泛型参数在编译过程中会被擦除,所以,对于Java虚拟机来说,实际上只有前三种类型。在类、接口和数组中,数组类是由Java虚拟机直接生成的,其他两种则有对应的字节流。字节流(也就是java编译器编译成的class文件)都会被加载到java虚拟机中,成为类或者接口(以下统称类)。
但是,无论是虚拟机直接生成的数组类,还是加载的类,java虚拟机都需要对其进行链接和初始化。

加载

   加载,就是指查找字节流,并且创建类的过程。对于数据类来说,他没有对应字节流,由java虚拟机直接生成。对于其他类来说,就需要java虚拟机借助类加载器来完成字节流查找的过程。
   关于类加载器主要分为三种,启动类加载器,扩展类加载器以及应用类加载器。在java虚拟机中,每当有一个类加载器接收到加载请求是,它会先将请求转发给父类加载器,在父类加载器没有找到所请求的类的情况下,该类加载器才会尝试去加载。这样的加载方式我们称之为双亲委派模型。
   在Java9之前,启动类加载器负责加载最为基础、最为重要的类(JRE的lib目录下jar包中的类)。扩展类加载器的父类加载器是启动类加载器,负责加载次要的但又通用的类(JRE的lib/ext目录下jar包中的类)。最后的应用类加载器的父类加载器是扩展类加载器,负责加载应用程序路径下的类。java9之后,扩展类加载器更名为平台类加载器,除了少数几个关键模块由启动类加载器加载外,其他模块均由平台类加载器所加载。

链接

   链接,是指将创建成的类合并至Java虚拟机中,使之能够执行的过程。它可分为验证、准备以及解析三个阶段。
   验证:验证的目的在于被加载的类能够满足Java虚拟机的规范。通常来说,通过Java编译器生成的类文件一定满足Java虚拟机的规范。(如果存在编译成字节码之后,反汇编修改了字节码的情况。可能就不满足Java虚拟机规范)
   准备:准备阶段则是为被加载的类的静态字段分配内存。Java代码中对静态字段的具体初始化,则会在接下来的初始化阶段中完成。当然,准备阶段除了会为静态字段分配内存之外,有些虚拟机还会例如实现虚方法的动态绑定的方法表等等。
   解析:在class文件被加载至Java虚拟机之前,这个类无知道其他类以及其方法、字段所对应的具体地址,甚至也不知道自己方法、字段的地址。所以,Java编译器在遇到需要引用成员时,会为其生成一个符号引用。在运行阶段,就可以通过该符号引用无歧义地定位到具体的目标之上。而解析阶段的目的就是讲这些符号引用解析成为实际地址引用。当然,如果符号引用指向了一个未被加载的类,或者未被加载的字段、方法,那么解析将会触发这个类的加载(但不一定会触发这个类的链接以及初始化的过程)
   PS:Java虚拟机规范中并没有要求在链接过程中完成解析。它仅规定了:如果某些字节码使用了符号引用,那么在执行这些字节码之前,需要对这些字节码符号引用进行解析。

初始化

   类加载的最后一步便是初始化了。在Java代码中,如果静态字段被final修饰,并且它的类型是基本类型或字符串时,那么该字段便会被Java编译器标记成常量值,其初始化过程由Java虚拟机直接完成。除此之外的赋值操作,以及所有静态代码块中的代码,则会被Java编译器优化到同一方法中,并把它命名为 <clinit >。初始化完成之后,类便成为可执行的状态。
关于类的初始化触发条件:
1.当虚拟机启动时,初始化用户指定的主类;
2.当遇到用以新建目标类实例的new指令时,初始化new指令的目标类;
3.当遇到调用静态方法的指令时,初始化该静态方法所在的类;
4.当遇到访问静态字段的指令时,初始化该静态字段所在的类;
5.子类的初始化会触发父类的初始化;
6.使用反射API对某个类进行反射调用时,初始化这个类;

实例操作
新建Singleton.java

public class Singleton {
  private Singleton() {}
  private static class LazyHolder {
    static final Singleton INSTANCE = new Singleton();
    static {
      System.out.println("LazyHolder.<clinit>");
    }
  }
  public static Object getInstance(boolean flag) {
    if (flag) return new LazyHolder[2];
    return LazyHolder.INSTANCE;
  }
  public static void main(String[] args) {
    getInstance(true);
    System.out.println("----");
    getInstance(false);
  }
} 

运行命令
javac Singleton.java
java -verbose:class Singleton
PS:-verbose:class可以打印类加载的先后顺序

image.png

从运行结果可以看出调用getInstance(true)时,也就是新建LazyHolder数组时,只加载的类,并没有初始化。初始化是在调用getInstance(false)时完成。同时也可以通过openjdk工具包中下载asmtools.jar工具来修改字节码,得出在修改了编译后的字节码后,调用getInstance(true)时也不会调用链接的过程(因为链接的第一步就是验证字节码是否符合JVM规范).
总结:新建引用类型类的数组时,只会加载,不会链接和初始化。链接和初始化在真正实例化的时候会触发。

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

推荐阅读更多精彩内容