class文件常量池・运行时常量池・字符串常量池 到底是啥?

本文详细介绍了Java中的常量池概念,包括变量、常量和字面量的定义,以及类文件常量池和运行时常量池的区别与联系。运行时常量池在方法区中存储符号引用和字面量,并在运行时可能动态添加常量。字符串常量池(StringPool)是Java堆中的一块区域,用于存储字符串字面量的引用。通过示例解释了String类的intern()方法如何与运行时常量池交互。
摘要由CSDN通过智能技术生成

读文献时候总冒出来各种关于Pool 的名词,一直被困扰,今天捋一捋

  • 变量(variable): a variable is a name that can represent different values during the execution of the program.
  • 常量(constant): a constant is a name that represents the same value throughout a program.
  • 字面量(literal ): a literal is not a name,it is the value itself。 如: x = 3 x is a variable, 3 is a literal。 参考 Literal
  • 字符串字面量(string literal): A string literal is a programming string in which characters exist as their literal value rather than a variable. They are denoted by delimiters. Delimiters are characters, often quotation marks or brackets, that contain a string literal。 例如: ” Hello World! “。( 参考 String Literal
  • 符号引用 (Symbolic References): 包括类和接口的全限定名、字段的名称和描述符、以及方法的名称和描述符。在类加载阶段,虚拟机会将常量池中的符号引用转换为直接引用
    在这里插入图片描述

class文件常量池(Constant Pool )

  1. JavaClass文件结构的设计目的是为了能让虚拟机以一种统一的方式来处理不同语言编译后的字节码。Class文件常量池Constant Pool Table)是其非常重要的一部分,它存储了编译期间生成的所有字面量符号引用

拓展请转阅
An Introduction to the Constant Pool in the JVM
The Constant Pool

# class文件常量池

public class ExampleClass {
    public static final String GREETING = "Hello, World!";
    public static void main(String[] args) {
        System.out.println(GREETING);
    }
}

执行 javap -verbose ExampleClass.class,展示了常量池的信息

Constant pool:
   #1 = Class              #2             // java/lang/Object
   #2 = Utf8               java/lang/Object
   #3 = Utf8               GREETING
   #4 = Utf8               Ljava/lang/String;
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Utf8               SourceFile
   #9 = Utf8               ExampleClass.java
  #10 = Utf8               Hello, World!
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               println
  #14 = Utf8               (Ljava/lang/String;)V
  #15 = Class              #16            // java/io/PrintStream
  #16 = Utf8               java/io/PrintStream
  #17 = Fieldref           #15.#18        // java/io/PrintStream:out:Ljava/io/PrintStream;
  #18 = NameAndType        #13:#14        // println:(Ljava/lang/String;)V
  #19 = Methodref          #15.#17        // java/io/PrintStream:println:(Ljava/lang/String;)V
  #20 = Utf8               <clinit>

在这里插入图片描述

运行时常量池(Runtime Constant Pool)

  1. Runtime Constant Pool in class files are certainly not enough, because we need to run in the JVM. The runtime constant pool is one-to-one corresponding to the constant pool of the class file, which is built by the constant pool of the class file.
    翻译:运行时常量池class文件常量池构建,与class文件常量池一对一对应。(参考: Runtime constant pool

  2. 运行时常量池 存储在方法区
    读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明

  3. 《Java虚拟机规范》对于运行时常量池并没有做任何细节的要求,不同提供商实现的虚拟机可以按照自己的需要来实现这个内存区域,不过一般来说,除了保存Class文件中描述的符号引用外,还会把由符号引用翻译出来的 直接引用 也存储在运行时常量池中。
    读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明

  4. 运行时常量池相对于Class文件常量池的另外一个重要特征是具备 动态性,Java语言并不要求常量一定只有编译期才能产生,也就是说,并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern() 方法。
    读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明

在这里插入图片描述

字符串常量池 String PoolString literal PoolString Constant Pool

  1. 字符串常量池中存储的是指向实际字符串对象的引用,而这些字符串对象实际存储在堆内存中。
  2. 运行时常量池 存储在方法区

拓展请转阅
String Pool in Java
Strings and String literals in String Literal Pool
常量池与方法区以及又读new String对象创建问题
What is Java String Pool?.
String pool vs Constant pool.


字符串常量池的一个小例子

String str1 = "abc";
String str2 = new String("def");
String str3 = "abc";
String str4 = str2.intern();
String str5 = "def";

System.out.println(str1 == str3); // true 
System.out.println(str2 == str4); // false 
System.out.println(str4 == str5); // true

1、解析str1的时候先查找string pool,发现里面没有”abc”的引用,就在堆里创建”abc”实例对象,然后把引用值存入string pool中。

2、第二句的时候会生成两个实例:先查string pool,因没有"def"的引用,堆里创建”def”实例对象,并且引用存入到StringTable中。另一个是new出来的一个值为”def”的实例对象,与上面那个是不同的实例。

3、当在解析str3的时候查找StringTable,里面有”abc”的引用,所以str3的引用地址与之前的那个已存在的相同。

4、 str4是在运行的时候调用intern()函数,返回StringTable”def”,如果没有就将str2的引用值添加进去,在这里,StringTable中已经有了”def”的引用值了,所以返回上面在new str2的时候添加到StringTable中的 “def”引用值。

5.最后str5在解析的时候就也是指向存在于StringTable中的”def”的引用值。

那么这样一分析之后,下面三个打印的值就容易理解了。

拓展请转阅
Java中几种常量池的区分
String::intern()介绍


[Q&A] 字符串常量池 和 运行时常量池 关系

  1. 字符串常量池运行时常量池 的一个子集,专门用于存储字符串字面量。
  2. 字符串常量池运行时常量池 同生命周期。
  3. 字符串常量池 主要用于优化字符串的存储和比较,而 运行时常量池 则更广泛地用于存储各种常量信息,支持类的动态链接和解析。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值