java静态池_Java中的常量池

本文详细解读Java中的三种常量池:字符串常量池在1.7后的变化,class常量池包含在.class文件中的字面量和符号引用,以及运行时常量池的迁移和结构。重点讲解了字符串常量池的intern方法和运行时常量池中静态常量与符号引用的解析过程。
摘要由CSDN通过智能技术生成

Java中的常量池分为三类:字符串常量池、class常量池、运行时常量池

字符串常量池

从1.7及其之后,字符串常量池从方法区移到了堆中

字符串池的实现——StringTable

String类中并没有Integer中IntegerCache对象池,String中有native方法intern()。

intern

intern()方法作用是:若字符串常量池中存在(通过#equals(Object)来判定是否存在)该字符串,则直接返回,否则,将该String对象添加到池中并返回它的引用。

/**

* Returns a canonical representation for the string object.

*

* A pool of strings, initially empty, is maintained privately by the

* class {@code String}.

*

* When the intern method is invoked, if the pool already contains a

* string equal to this {@code String} object as determined by

* the {@link #equals(Object)} method, then the string from the pool is

* returned. Otherwise, this {@code String} object is added to the

* pool and a reference to this {@code String} object is returned.

*

* It follows that for any two strings {@code s} and {@code t},

* {@code s.intern() == t.intern()} is {@code true}

* if and only if {@code s.equals(t)} is {@code true}.

*

* All literal strings and string-valued constant expressions are

* interned. String literals are defined in section 3.10.5 of the

* The Java™ Language Specification.

*

* @return a string that has the same contents as this string, but is

* guaranteed to be from a pool of unique strings.

*/

public native String intern();

intern()

class常量池

class文件是一组以字节为单位的二进制数据流,当java代码被编译为.class文件格式时,二进制数据存放在磁盘中,其中就包括class文件常量池。

class常量池包含字面量和符号引用

1f7c61712d61

image.png

public class HelloWorld {

public static void main(String[] args) {

String s = "Hollis";

}

}

javac 生成HelloWorld.class文件,然后javap -v HelloWorld.class

常量池内容如下:

1f7c61712d61

image.png

Java代码在编译时,并不会“拼接”好完整执行文件,而是在虚拟机加载class文件时动态连接。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址中。

运行时常量池

Java1.7之前是在方法区,也处于永久代中;Java1.7因为使用永久代存在内存泄漏问题,将永久代中的运行时常量池移动到堆内存中;Java1.8是在元空间。

只有class文件中的常量池肯定是不够的,因为我们需要在JVM中运行起来。这时候就需要一个运行时常量池,为JVM的运行服务。

运行时常量池跟class文件的常量池一一对应,它是根据class常量池来构建的。

运行时常量池分两种类型:符号引用和静态常量

String s = "a";

s就是符号引用,需要在运行期进行解析,而a是静态常量,它是不会发生变化的。

静态常量详解

运行时常量池中的静态常量是从class文件中的constant_pool构建的,可以分为两部分:String常量和数字常量。

String常量

String常量是对String对象的引用,是从class中的CONSTANT_String_info结构构建的:

CONSTANT_String_info {

u1 tag;

u2 string_index;

}

tag是结构体的标记,string_index是string在class常量池中的index。

string_index对应的class常量池的内容是一个CONSTANT_Utf8_info结构体。

CONSTANT_Utf8_info {

u1 tag;

u2 length;

u1 bytes[length];

}

CONSTANT_Utf8_info是啥呢?它就是要创建的String对象的变种UTF-8编码。

我们知道unicode的范围是从0x0000 至 0x10FFFF。

变种UTF-8就是将unicode进行编码的方式。那是怎么编码呢?

1f7c61712d61

image.png

上面这个图说实话,我没怎么看懂,TODO待学习

CONSTANT_String_info运行时String常量的规则(inter):

如果String.intern之前被调用过,并且返回的结果和CONSTANT_String_info中保存的编码是一致的话,表示他们指向的是同一个String的实例。

如果不同的话,那么会创建一个新的String实例,并将运行时String常量指向该String的实例。最后会在这个String实例上调用String的intern方法。调用inter方法主要是将这个String实例加入字符串常量池。

数字常量

数字常量是从class文件中的CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_Long_info和 CONSTANT_Double_info 构建的。

符号引用详解

符号引用也是从class中的constant_pool中构建的。

对class和interface的符号引用来自于CONSTANT_Class_info。

对class和interface中字段的引用来自于CONSTANT_Fieldref_info。

class中方法的引用来自于CONSTANT_Methodref_info。

interface中方法的引用来自于CONSTANT_InterfaceMethodref_info。

对方法句柄的引用来自于CONSTANT_MethodHandle_info。

对方法类型的引用来自于CONSTANT_MethodType_info。

对动态计算常量的符号引用来自于CONSTANT_MethodType_info。

对动态计算的call site的引用来自于CONSTANT_InvokeDynamic_info。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值