前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Java 虚拟机原理】Java 类中的类加载初始化细节 ( 只使用类中的常量时加载类不会执行到 ‘初始化‘ 阶段 )

【Java 虚拟机原理】Java 类中的类加载初始化细节 ( 只使用类中的常量时加载类不会执行到 ‘初始化‘ 阶段 )

作者头像
韩曙亮
发布2023-03-29 16:46:59
3.6K0
发布2023-03-29 16:46:59
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

一、类加载初始化时机


类加载时机 : Java 程序执行时 , 并不是一开始将所有的字节码文件都加载到内存中 , 而是用到时才进行加载 ;

  • 通过 new 关键字创建实例对象 ;
  • 通过 Class 反射 获取类 ; 如 : Class.forName(“Xxx”) 获取类 ;
  • 序列化 / 反序列化 ;
  • 调用 clone 克隆对象 ;
  • 有 main 函数的类 , 会默认自动加载 ;
  • 调用子类 , 如果之前没有加载过父类 , 则 自动加载父类 ;
  • 访问 类 的 静态变量
在这里插入图片描述
在这里插入图片描述

有些类加载操作 , 不需要执行 加载 -> 连接 ( 验证 , 准备 , 解析 ) -> 初始化 这个完整的流程 ;

如 : 如果是 public final static 修饰的常量值 , 在编译阶段 , 就会将该值放到常量池中 ; 在类加载的过程中 , 只要执行到 加载 -> 连接 ( 验证 , 准备 , 解析 ) 阶段 , 就可以完成常量池的初始化 , 即使没有执行 初始化 这个步骤 , 也不影响使用类中的常量值 ;

在 连接 的 准备 阶段 , 为 普通 的 静态变量 进行 默认赋值 , 但是针对 静态常量 , 直接进行 指定赋值 ;

但是 普通的 静态变量 的 指定赋值 , 是在 初始化 阶段 完成的 ;

类 在 " 初始化 " 阶段 , 调用 静态代码块 ;

二、常量加载示例


类加载时 , 如果只用到了类中的常量 , 则只进行 " 加载 -> 连接 ( 验证 , 准备 , 解析 ) " 两个过程 :

代码语言:javascript
复制
public class Student {
    // 常量
    public static final int age = 18;

    static {
        // 加载类的 " 初始化 " 阶段才执行 静态代码块
        //  如果只是进行了 " 连接 " , 没有进行 初始化 , 则不会调用该代码块
        System.out.println("Student 静态代码块调用");
    }
}

主函数 :

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        int age = Student.age;
        System.out.println("main 函数 age = " + age);
    }
}

执行结果 :

在这里插入图片描述
在这里插入图片描述

上述 Student 类中的 静态代码块 没有被执行 , 说明 类加载 的流程中 , " 初始化 " 步骤 , 没有被执行 ;

找到 Student.class 字节码文件 , 然后使用

代码语言:javascript
复制
javap -v -Student.class

查看该字节码文件的附加信息 ;

在 " 常量表 " 中 , 发现了常量值

18

, 这个常量值是在编译阶段就编译到了字节码中 ; 在 " 连接 " 的 " 准备 " 阶段 , 该常量值就设置完毕 ; 出于最大限度性能优化的考虑 , 如果不使用该类的其它值 , 就不会执行 " 初始化 " 阶段 ; 因此这里不会调用 静态代码块 中的代码 ;

代码语言:javascript
复制
Constant pool:
  #10 = Integer            18
在这里插入图片描述
在这里插入图片描述

三、数组加载示例


对数组进行创建操作 , 如创建了一个对象数组 , 此时不会加载该对象对应的类 , 只会为其在内存分配空间 ;

创建数组时 , 触发的是 Student[] 数组类型的 类加载初始化 , 但是不会触发 Student 类的初始化操作 ;

如果调用数组中的元素时 , 就需要初始化 Student 类 ;

Student 类 :

代码语言:javascript
复制
public class Student {
    // 常量
    public static final int age = 18;

    static {
        // 加载类的 " 初始化 " 阶段才执行 静态代码块
        //  如果只是进行了 " 连接 " , 没有进行 初始化 , 则不会调用该代码块
        System.out.println("Student 静态代码块调用");
    }
}

main 函数 :

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        System.out.println("main 函数执行");
        Student[] students = new Student[2];
    }
}

执行结果 : 只是创建数组 , 只需要为其分配内存空间 , 不需要为每个 Student 数组元素赋值 , 这里不需要初始化 Student 类 ;

在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、类加载初始化时机
  • 二、常量加载示例
  • 三、数组加载示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档