深入理解JVM-类加载初始化阶段-类的主动与被动引用

JVM的类加载阶段中初始化阶段   P210

  虚拟机规定的五种情况必须对类的“初始化”情况

  1.遇到new、getstatic、putstatic、或invokestic 四条字节码指令时,如果类没有经过初始化,则需要先触发使其初始化,生成这四条指令的最常见的java代码场景时:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰,已在编译器把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。

  2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化则需要先触发其初始化。

  3.当初始化一个类的时候,入宫发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

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

  5.当使用JDK7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。

这五种情况属于------对一个类进行主动引用。

  除此之外,所有引用类的方式都不会触发初始化,成为被动引用

  一、通过子类引用父类的静态字段,不会导致字类初始化

public class SuperClass {    public static int value = 123;    static {        System.out.println("SuperClass init!!!");    }}
public class SubClass extends SuperClass {    static {        System.out.println("SubClass init!!");    }}
public class InitTest {    public static void main(String[] args) {        System.out.println(SubClass.value);    }}// 输出// 子类调用父类的静态遍历,致使触发父类初始化,但是子类初始化未调用

可以打印出类的加载顺序,可以用来排查 class 的冲突问题:

-XX:+TraceClassLoading

  二、通过数组定义来引用类,不会触发此类的初始化

public static void main(String[] args) {    SuperClass[] sca = new SuperClass[10];}运行后没有触发"SuperClass init"但是newarray触发

 

三、常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量类的初始化

public class ConstClass {    static {        System.out.println("ConstClass init!!!");

    public static final String HELLOWORLD = "hello world";}
public static void main3(String[] args) {    System.out.println(ConstClass.HELLOWORLD);}没有触发"ConstClass init!!!"  虽然在Java源码中引用了ConstClass类中的常量HELLOWORLD,但其实在编译阶段通过常量传播优化,已经将此常量ConstClass.HELLOWORLD的引用实际都被转化成InitTest类对自身常量池的引用了。

  ps:

  调用 javap -c xx.class查看字节码 <https://www.jianshu.com/p/6a8997560b05>

  字节码大全 <https://www.cnblogs.com/longjee/p/8675771.html>

原文地址:https://www.cnblogs.com/huan30/p/11774102.html

时间: 2024-10-05 04:58:53

深入理解JVM-类加载初始化阶段-类的主动与被动引用的相关文章

深入理解JVM虚拟机6:深入理解JVM类加载机制

深入理解JVM类加载机制 简述:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 下面我们具体来看类加载的过程: 类的生命周期 类从被加载到内存中开始,到卸载出内存,经历了加载.连接.初始化.使用四个阶段,其中连接又包含了验证.准备.解析三个步骤.这些步骤总体上是按照图中顺序进行的,但是Java语言本身支持运行时绑定,所以解析阶段也可以是在初始化之后进行的.以上顺序都只是说开始的顺序,实际过

【深入理解JVM】:Java类继承关系中的初始化顺序

Java类初始化的顺序经常让人犯迷糊,现在本文尝试着从JVM的角度,对Java非继承和继承关系中类的初始化顺序进行试验,尝试给出JVM角度的解释. 非继承关系中的初始化顺序 对于非继承关系,主类InitialOrderWithoutExtend中包含了静态成员变量(类变量)SampleClass 类的一个实例,普通成员变量SampleClass 类的2个实例(在程序中的顺序不一样)以及一个静态代码块,其中静态代码块中如果静态成员变量sam不为空,则改变sam的引用.main()方法中创建了2个主

深入Java虚拟机JVM类加载初始化学习笔记

1. Classloader的作用,概括来说就是将编译后的class装载.加载到机器内存中,为了以后的程序的执行提供前提条件. 2. 一段程序引发的思考: 风中叶老师在他的视频中给了我们一段程序,号称是世界上所有的Java程序员都会犯的错误. 一般不假思索的结论就是,a=1,b=1.给出的原因是:a.b都是静态变量,在构造函数调用的时候已经对a和b都加1了.答案就都是1.但是运行完后答案却是a=1,b=0. 为什么呢,这3句无非就是静态变量的声明.初始化,值的变化和声明的顺序还有关系吗?Java

【深入理解JVM】:类加载机制

概述 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 与那些在编译时需要进行链接工作的语言不同,在Java语言里,类型的加载.连接和初始化过程都是在程序运行期间完成的,例如import java.util.*下面包含很多类,但是,在程序运行的时候,虚拟机只会加载哪些我们程序需要的类.这种策略虽然会令类加载时稍微增加一些性能开销,但是会为Java应用程序提供高度的灵活性. 类加载的时机 类从

【深入理解JVM】:解析与分派

解析 Java中方法调用的目标方法在Class文件里面都是常量池中的符号引用,在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用.(关于符号引用与直接引用,详见[深入理解JVM]:Class类文件结构)这种解析的前提是:方法在程序真正运行之前就有一个可以确定的调用版本,并且这个方法的调用版本在运行期是不可改变的,即"编译期可知,运行期不可变",这类目标的方法的调用称为解析(Resolve). 只要能被invokestatic和invokespecial指令调用的方法,都可以在解

JVM类加载机制一

类加载的过程 什么是类加载?Java编译器会将我们编写好的代码编译成class字节码文件,JVM会把这些class字节码文件加载到内存中,并对加载的数据进行校验.准备.解析并初始化,这个过程就是类加载机制.类加载分为三个阶段:加载,连接,初始化. 这三个阶段都是在程序运行期间完成的.其中加载,校验,准备,初始化,卸载的顺序都是确定的,解析可能会在初始化之后完成. JVM 可以选择符号引用解析的时机,一种是当类文件加载并校验通过后,这种解析方式被称为饥饿方式.另外一种是符号引用在第一次使用的时候被

从排查一个登录问题看jvm类加载机制

问题来源 这段时间我们在切换某海外环境的登录体系,遇到一个应用会话校验有问题,排查过程如下: 从会话逻辑trace去看,走到了tair获取session的代码里,实例代码如下: public class SessionManagerProxyImpl implements CnSessionManagerProxy { private volatile static Map<String,SessionManager> sessionManagerMap = Maps.newHashMap()

JVM类加载以及执行的实战

前几篇文章主要是去理解JVM类加载的原理和应用,这一回讲一个可以自己动手的例子,希望能从头到尾的理解类加载以及执行的整个过程. 这个例子是从周志明的著作<深入理解Java虚拟机>第9章里抄来的.原作者因为有丰富的经验,可以站在一个很高的高度去描述整个过程.而我只能以现有的水平,简单的理解这个例子. 如果读者感觉不错,那都是原作者的智慧:如果觉得不过尔尔,那就是我水平有限. 先说说日志.原先,我特别不喜欢在自己的程序里输出日志.写的时候那叫一个爽,可是一旦运行出错,那就麻烦了.因为不知道具体执行

深入理解JVM读书笔记: Class类文件结构

Class文件是一组以8位字节为基础单位的二进制流.采用一种类似于C语言结构体的微结构来存储数据,只有两种数据类型:无符号数和表.其中无符号数数据基本的数据类型,以u1.u2.u4.u8表示1.2.4.8字节的无符号数,用于描述数字.索引引用.数量值或者UTF-8编码字符串:表则是由无符号树和其他表的复合数据类型,以_info后缀.整个Class文件本质上就是一张表: 解析Class文件各个数据项含义: 魔数 头4个字节为魔数Magic Number,唯一作用是识别文件是否能被虚拟机接受. 版本