JVM-02-类的生命周期

88 阅读3分钟

跟孙哥学java

孙哥主页

类的生命周期 描述一个类加载,使用,卸载的整个过程

生命周期的概述

image.png

连接又可以拆分成 image.png

加载阶段

  1. 加载阶段 第一步是类加载器 根据类的全限定名 通过不同的渠道以二进制流的方式获取字节码信息。程序员可以编码选择不同渠道

image.png 比如Spring常用到动态代理技术 早期Applet技术 通过网络传输的类

  1. 类加载器在加载完类之后,Java虚拟机讲字节码信息保存到方法区中

生成一个InstancKlass对象,保存类的所有信息,里面还包含实现特定功能比如多态的信息。 image.png

  1. Java虚拟机在堆中生成一封与方法区中数据类似的Java.lang.Class对象

image.png 对于开发者来说,只需要访问堆中的Clss对象而不需要访问方法区中所有信息。 这样ava虚拟机就能很好地控制开发者访问数据的范围。提升数据的安全性

连接阶段

  1. 验证

验证内容是否满足Java虚拟机规范 主要包含如下四部分,具体见《Java虚拟机规范》

  • 文件格式校验 如 0xCAFEBABE 开头,主次版本号是否满足Java虚拟机版本要求

image.png class文件的主副版本号都不能超过java虚拟机的主副版本号

  • 元信息验证,例如类必须有父类(super不能为空)
  • 验证程序执行指令的语义,比如方法内的指令执行跳转到其他方法
  • 符号引用验证,例如是否访问了其他类的private的方法
  1. 准备

给静态变量赋初值,防止该变量存在残留值。 image.png final修饰的基本数据类型的静态变量,在准备阶段就会进行赋值

  1. 解析

将常量池中的符号引用替换成内存的直接引用 直接引用不在使用编号,而是使用地址直接访问内存

初始化阶段

对于非final修饰的静态变量,会由虚拟机给变量赋予初值

在初始化阶段: 会执行静态代码块中的代码,并为静态变量赋值 初始化阶段会执行字节码文件中clinit部分的字节码指令 putstatic---> 给静态变量赋值

image.png 执行过程: 将1 放入操作数栈中 putstatic,将操作数栈中的1赋值给 常量池中编号为2的变量 将2放入操作数栈中 给常量池 编号为2的变量赋值为2

以下方式会导致类的初始化: 1.访问一个类的静态变量或者静态方法,注意变量是finl修饰的并且等号右边是常量不会触发初始化。 2.调用Class.forName(String className)。 3.new一个该类的对象时。 4.执行Main方法的当前类的静态变量。 image.png

clinit指令在特定情况下不会出现,比如:如下几种情况是不会进行初始化指令执行的。 1.无静态代码块且无静态变量赋值语句。 2.有静态变量的声明,但是没有赋值语句。 3.静态变量的定义使用final关键字,这类变量会在准备阶段直接进行初始化。

注意: 直接访问父类的静态变量,不会触发子类的初始化。 子类的初始化clinit调用之前,会先调用父类的clinit初始化方法。

面试题

程序的输出结果是什么? image.png

输出: D A C B C B

image.png image.png image.png