IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java类加载的过程 -> 正文阅读

[Java知识库]Java类加载的过程

类的生命周期

一个类从从被加载到JVM内存开始,到卸载出内存为止,它的整个生命周期会经历七个阶段,其中验证、准备、解析统称为连接。
加载、验证、准备、初始化、卸载这五个阶段的顺序是固定的,解析阶段在某些情况下会在初始化阶段之后进行。

在《java虚拟机规范》中严格规定了有且只有六种情况必须立即对类进行加载、验证、准备、初始化(下文所说的初始化阶段是这四个阶段的简称):

  1. 遇到new、getstatic、putstatic或invokestatic 这四条字节码指令时,如果类型没有进行过初始化,则需要先触发其初始化阶段。能够生成这四条指令的场景有:
    – 使用new关键字实例化对象的时候。
    – 读取或设置一个类型的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候。
    – 调用一个类型的静态方法的时候。
  2. 使用java.lang.reflect包的方法对类型进行反射调用的时候,如果类型没有进行过初始化,则需要先触发其初始化。
  3. 当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
  4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
  5. 当使用JDK7新加入的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。
  6. 当一个接口中定义了JDK8新加入的默认方法(被default关键字修饰的接口方法)时,如果有这个接口的实现类发生了初始化,那该接口要在其之前被初始化。

类加载的过程

加载

Loading(加载)阶段阶段是"类加载"过程中的一个阶段,加载和类加载是两个概念,加载的动作由类加载器来完成。

在加载阶段JVM主要完成三件事情:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流。
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

验证

验证是连接阶段的第一步,这一介段的目的是确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害JVM自身的安全。

准备

准备阶段是正式为类中定义的静态变量分配内存并设置变量初始值的阶段。例如:

private static String str = "abc";

在此阶段后str为初始值null而不是"abc"。

解析

解析阶段是JVM将常量池内的符号引用替换为直接引用的过程。在Class文件中它以 CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodlref_info等类型的常量出现,此阶段后会变成指向目标的指针。

初始化

在准备阶段静态变量设置了初始值,在初始化阶段就是给变量赋值的过程,有继承关系先初始化父类,多个初始化语句依次执行

一道常见的面试题

示例1

public class Test {
    public static int num = 10;
    public static Test t = new Test();

    public Test(){
        num++;
    }
}
public static void main(String[] args) {
    System.out.println(Test.num);
}

运行结果

11

Process finished with exit code 0

示例2

public class Test {
    public static Test t = new Test();
    public static int num = 10;

    public Test(){
        num++;
    }
}
public static void main(String[] args) {
    System.out.println(Test.num);
}

运行结果

10

Process finished with exit code 0

发现两个静态变量换一个顺序,输出的结果就不一样了。这是为什么呢?

在示例1中,经过准备阶段后num =0;t=null;,到初始化阶段的时候,由于tnum上面t会先初始化,t初始化对象num++,num有0变成了1,之后num初始化赋值为10,初始化结束,所以输出num为10;
在示例2中,经过准备阶段后num =0;t=null;,到初始化阶段的时候,由于numt上面num会先初始化,num初始化赋值为10,之后t初始化对象num++,num有10变成了11,初始化结束,所以输出num为11。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:09:53  更:2022-04-09 18:13:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:42:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码