2200字带你学习JVM类加载的第三个阶段(初始化)

往期推荐

2000字带你学习JVM类加载的第一个步骤(Loading字节码)

4分钟带你看懂JVM类加载的第二个过程之Linking(链接阶段)

子类加载前先加载父类?

    在加载一个类之前,虚拟机总是会试图加载该类的父类,因此父类的<clinit>总是在子类<clinit>之前被调用。也就是说,父类的static块优先级高于子类。 

口诀:由父及子,静态先行。

哪些类不会生成<clinit>方法?

Java编译器并不会为所有的类都产生<clinit>()初始化方法。

哪些类在编译为字节码后,字节码文件中将不会包含<clinit>()方法?

  1. 一个类中并没有声明任何的类变量,也没有静态代码块时

  2. 一个类中声明类变量,但是没有明确使用类变量的初始化语句以及静态代码块来执行初始化操作时

  3. 一个类中包含static final修饰的基本数据类型的字段,这些类字段初始化语句采用编译时常量表达式

<clinit>()的调用会死锁吗?

    对于<clinit>()方法的调用,也就是类的初始化,虚拟机会在内部确保其多线程环境中的安全性。

    虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。

    正是因为函数<clinit>()带锁线程安全的,因此,如果在一个类的<clinit>()方法中有耗时很长的操作,就可能造成多个线程阻塞,引发死锁。并且这种死锁是很难发现的,因为看起来它们并没有可用的锁信息。

    如果之前的线程成功加载了类,则等在队列中的线程就没有机会再执行<clinit>()方法了。那么,当需要使用这个类时,虚拟机会直接返回给它已经准备好的信息。

类的初始化情况:主动使用vs被动使用

Java程序对类的使用分为两种:主动使用 和 被动使用。

主动使用的情况:

主动使用的说明:

    Class只有在必须要首次使用的时候才会被装载,Java虚拟机不会无条件地装载Class类型。Java虚拟机规定,一个类或接口在初次使用前,必须要进行初始化。这里指的“使用”,是指主动使用。

主动使用只有下列几种情况:(即:如果出现如下的情况,则会对类进行初始化操作。而初始化操作之前的加载、验证、准备已经完成。)

1. 当创建一个类的实例时,比如使用new关键字,或者通过反射、克隆、反序列化。

2. 当调用类的静态方法时,即当使用了字节码invokestatic指令。

3. 当使用类、接口的静态字段时(final修饰特殊考虑),比如,使用getstatic或者putstatic指令。

4. 当使用java.lang.reflect包中的方法反射类的方法时。比如:Class.forName("com.atguigu.java.Test")

5. 当初始化子类时,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

6. 如果一个接口定义了default方法,那么直接实现或者间接实现该接口的类的初始化,该接口要在其之前被初始化。

7. 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。

8. 当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类。(涉及解析REF_getStatic、REF_putStatic、REF_invokeStatic方法句柄对应的类)

 被动使用的情况

被动使用的情况

    除了以上的情况属于主动使用,其他的情况均属于被动使用。被动使用不会引起类的初始化。

    也就是说:并不是在代码中出现的类,就一定会被加载或者初始化。如果不符合主动使用的条件,类就不会初始化。

1. 当访问一个静态字段时,只有真正声明这个字段的类才会被初始化。

当通过子类引用父类的静态变量,不会导致子类初始化

2. 通过数组定义类引用,不会触发此类的初始化

3. 引用常量不会触发此类或接口的初始化。因为常量在链接阶段就已经被显式赋值了。

4. 调用ClassLoader类的loadClass()方法加载一个类,并不是对类的主动使用,不会导致类的初始化。

> 被动的使用,意味着不需要执行初始化环节,意味着没有<clinit>()的调用。

如果针对代码,设置参数-XX:+TraceClassLoading,可以追踪类的加载信息并打印出来。

本章面试题

  • 类加载的时机 (百度)

  • Class的forName("Java.lang.String")和Class的getClassLoader()的loadClass("Java.lang.String")有什么区别?  (百度)

  • 哪些情况会触发类的加载?(京东)

  • 类的加载 = 装载+链接(①②③)+初始化

关注公众号可免费加入大数据学习社群,2021版大数据高薪就业宝典(LeetCode数据库相关题库+大厂大数据面试题108套),还有 大数据笔面试套装(大量面试题+面试技巧+大数据简历模板),还有博主总结的大数据面试宝典脑图合集,涉及14个组件。关注公众号获取哦~

获取方式:关注公众号:大数据面试宝典,回复:666,就可以获得这份超级大礼!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值