JVM之常量池(字符串)

1     前言

本文主要从编译后的Java语言的字节码类文件格式与结构方面论述JVM常量池的相关特性。顾名思义,常量池主要用于JVM运行时保存类执行文件中的各种常量,有些常量是在编译阶段优化生成而在运行时加载,有些常量是关于类的基本信息或者属性信息,有些常量在运行时作为JVM指令的操作数,后面章节将展开详细的论述。

2     类文件组织结构

Java语言源文件是程序代码的文本文件,经JVM编译,生成以字节码(二进制)的形式表示而非文本形式表示的类文件,文件中包含可执行的JVM指令以及类属性、类方法以及类相关的元数据信息,其中JVM指令是一种类似计算机的指令,包括指令操作码、指令操作数,JVM在运行时使用类加载器加载该字节码类文件,JVM运行的应用执行业务逻辑处理时调用该类文件中的方法。

由于JVM是使用C语言开发,字节码类文件是以C语言数据结构组织存储,其数据结构如下所示:

其中,u2、u4是基本的无符号存储单元,u2表示2个字节占用空间,u4表示4个字节占用空间,其他是类型是基本存储单元的连续存储单元,下表是对各字段的简要说明。

字段名称

字段类型

字段描述

magic

u4

这个字段使用固定的值:0xCAFEBABE,其表示的意义类文件的格式

minor_version

u2

类文件小版本号

major_version

u2

类文件大版本号

constant_pool_count

u2

常量池大小

constant_pool[constant_pool_count-1]

cp_info

常量池数组

access_flags

u2

访问权限标识

this_class

u2

常量池的一个索引值,对应常量池的实体表示类的信息

super_class

u2

常量池的一个索引值,对应常量池的实体表示类的继承类

interfaces_count

u2

类实现的接口数量

interfaces[interfaces_count]

u2

类实现的接口数组

fields_count

u2

类域(类变量或者实例变量)的数量

fields[fields_count]

field_info

类域数组

methods_count

u2

类或者接口方法的数量

methods[methods_count]

method_info

类或者接口方法数组

attributes_count

u2

属性的数量

attributes[attributes_count]

attribute_info

属性数组

2.1   常量池大小

constant_pool_count该值等于constant_pool数组的长度加1。

2.2   常量池数组

常量池也叫常量表,实际上是一个数组,数组存储的实体表示各种不同的字符串常量、类或者接口名称及其属性域、类结构及其类子结构中涉及到的常量。其中,每个实体的起始字节表示其常量的类型。常量池的索引值的范围大于或等于1,小于或等于constant_pool_count-1。

3     常量池实体数据结构

常量池实体的数据结构如下所示:

其中,字段tag标识实体的类型,字段info[]标识指定实体的附加信息,该附加信息根据实体类型的不同而不同。

下表列出常量池中的实体类型:

如上表所示,其中,Constant Kind列表示常量的字面描述类型,Tag列表示常量池实体数据结构中的值类型,class file format列表示支持对应类型的类文件初始版本,Java SE列表示支持对应类型的的JDK初始版本。

JVM指令是以索引的方式从常量池中读取操作数常量,用于压入栈参与运算的,下表列出可用于栈参与运算的常量池实体类型:

4     字符串类型常量

字符串类型常量的数据结构如下所示:

以上数据结构作为字节序列存储在常量池实体类型数据结构cp_info的字段info数组中。其中tag的值等于8,string_index对应常量池的索引值,该索引值对应的实体是字符串常量所表示的通用数据结构CONSTANT_Utf8_info,该通用字符串数据结构如下所示:

在以上数据结构中,tag的值等于1,length表示bytes[length]数组的长度,bytes是存储字符串常量的字节序列数组。

5     字符串运算

在JDK中,字符串是一个常量,是java.lang.String类的实例化对象,并且所有常量表达式都是指向同一个常量,如下代码样例展示字符串常量的对比分析。

由以上的分析可知:

  • 同一个类包同一类下的相同字符串指向同一字符串对象

  • 同一个类包不同类下的相同字符串指向同一个字符串对象

  • 不同类包不同类下的相同字符串指向同一个字符串对象

  • 常量表达式是在编译阶段实行计算,其指向同一个字符串对象

  • 使用连接操作符号(+)连接字符串(非常量表达式),是在运行时阶段实行计算,其指向不同的字符串对象

  • 使用字符串intern()方法显式地计算,其指向同一个字符串对象

其中,"Hel" + "lo"是常量表达式,而"Hel" + lo不是常量表达式。

6     常量池字节码

下图代码样例展示常量表达式的字节码,表示在编译阶段生成字符串常量t=”abc”,并且在常量池中的索引地址是#19,其中,JVM指令ldc表示从常量池中取操作数实行压栈操作。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangys2006

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值