目录
读文献时候总冒出来各种关于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 )
- 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)
-
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 tothe constant pool of the class file
, which is built bythe constant pool
of the class file.
翻译:运行时常量池
由class文件常量池
构建,与class文件常量池
一对一对应。(参考: Runtime constant pool) -
运行时常量池 存储在方法区。
读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明 -
《Java虚拟机规范》对于运行时常量池并没有做任何细节的要求,不同提供商实现的虚拟机可以按照自己的需要来实现这个内存区域,不过一般来说,除了保存Class文件中描述的符号引用外,还会把由符号引用翻译出来的 直接引用 也存储在运行时常量池中。
读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明 -
运行时常量池相对于Class文件常量池的另外一个重要特征是具备 动态性,Java语言并不要求常量一定只有编译期才能产生,也就是说,并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern() 方法。
读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明
字符串常量池 String Pool・String literal Pool・String Constant Pool
- 字符串常量池中存储的是指向实际字符串对象的引用,而这些字符串对象实际存储在堆内存中。
- 运行时常量池 存储在方法区。
拓展请转阅
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] 字符串常量池 和 运行时常量池 关系
- 字符串常量池 是 运行时常量池 的一个子集,专门用于存储字符串字面量。
- 字符串常量池 和 运行时常量池 和 类 同生命周期。
- 字符串常量池 主要用于优化字符串的存储和比较,而 运行时常量池 则更广泛地用于存储各种常量信息,支持类的动态链接和解析。