Java虚拟机——类加载机制概述 & 类加载的时机

  • 在Class文件中描述的各类信息,最终都需要加载到虚拟机中之后才能被运行和使用。
  • 本章将会介绍虚拟机如何加载这些Class文件,Class文件中的信息进入到虚拟机后会发生什么变化。
  • 类加载机制:Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被Java虚拟机直接使用的Java类型。
  1. Class文件都有代表着Java语言中的一个类或接口的可能。
  2. Class文件不是特指某个存在于具体磁盘中的文件,而应当是一串二进制字节流。

7.2 类加载的时机

  • 一个类型从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期会经历加载、验证准备解析、初始化、使用和卸载七个阶段。
  • 其中验证、准备、解析三个部分统称为连接
  • 此外加载、验证、准备、初始化、卸载这五个阶段的顺序是确定的。
  1. 解析阶段:它在某些情况下可以发生在初始化之后,这是为了支持Java语言的运行时绑定特性(也称为动态绑定或晚期绑定)

什么情况下,需要开始类加载过程的第一个阶段"加载?

  • Java虚拟机规范中没有进行强制约束,这点可以交给虚拟机的具体实现来自由把握。
  • 但是对于初始化阶段,*严格规定了有且只有这六种情况必须立刻对类进行初始化。(而加载、验证、准备自然需要发生在此之前开始)
  1. 遇到newgetstaticputstaticinvokestatic这四条字节码指令时。如果类型没有进行过初始化,则需要先触发初始化
    (1). 使用new关键字实例化对象的时候
    (2). 读取或设置一个类型的静态字段
    (3). 调用一个类型的静态方法
  2. 使用java.lang.reflect包的方法对类型进行反射调用的时候。如果类型没有进行过初始化,则需要先触发初始化
  3. 当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化
  4. 当虚拟机启动的时候,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个类。
  5. 当一个接口中定义了被default关键字修饰的接口方法时,如果有这个接口的实现类发生了初始化,那么接口要在其之前完成初始化
  6. 使用了JDK7新加入动态语言支持时…
  • 这六种场景中的行为称为对一个类型的主动引用。

被动引用

  • 除了上面的六种场景之外,所有的引用类型的方式都不会触发初始化,称为被动引用。
  1. 通过子类引用父类的静态字段
  • 通过子类来引用父类中定义的静态字段,只会初始化父类,不会初始化子类
public class SuperClass {
    static {
        System.out.println("SuperClass init!");
    }
    public static int value = 123;
}

public class SubClass extends SuperClass{
    static {
        System.out.println("SubClass init!");
    }
}

public class NotInitialization {
    public static void main(String[] args) {
        System.out.println(SubClass.value);
    }
}

在这里插入图片描述

  1. 通过数组定义来引用类,不会触发此类的初始化
  • 什么东西都没有输出
public class NotInitialization {
    public static void main(String[] args) {
        SuperClass[]  sca = new SuperClass[10];
    }
}

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

public class ConstClass {
    static {
        System.out.println("ConstClass init!");
    }
    public static final String HELLOWORLD = "hello world";
}

public class NotInitialization {
    public static void main(String[] args) {
        System.out.println(ConstClass.HELLOWORLD);
    }
}
  • 什么都不会输出
  • 在编译期间,通过常量池的传播优化,已经将此常量值"hello world"直接存储在NotInitialization类的常量池中,
  • 以及NotInitialization对常量ConstClass.HELLOWORLD的引用,实际上都被转化为NotInitialization类对自身常量池的引用。

使用和卸载

  • 在一个数据类型完成类加载只会,开发者可以调用它的静态类成员或者使用new关键字来创建对象实例。

  • 当类满足三个条件时,这个类的生命周期就结束了,会被卸载。

  1. 该类的所有实例都已经被回收,Java堆中不存在该类的任何实例。
  2. 加载该类的ClassLoader(类加载器)已经被回收
  3. 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值