`
slevin1994
  • 浏览: 1382 次
社区版块
存档分类
最新评论

JVM运行时常量池与String池

    博客分类:
  • JVM
阅读更多
内容原创,欢迎指正,转载注明http://slevin1994.iteye.com/blog/2415778

字面常量
《Java语言规范 基于Java SE 8》3.10节 写道
字面常量是类型为简单类型,String类型和空类型的**值**在源程序中的表示。包括整数字面常量,浮点数字面常量,布尔字面常量,字符字面常量,字符串字面常量和空字面常量。
  • 整数字面常量,它的类型是long或者int(基本类型)
  • 浮点数字面常量,它的类型是float或者double(基本类型)
  • 布尔字面常量,它的类型是boolean(基本类型)
  • 字符字面常量,它的类型是char(基本类型)
  • 字符串字面常量,它的类型是String,是对String类的实例的引用(引用类型)
  • 空字面常量,总是空类型

《Java语言规范 基于Java SE 8》3.10.5节 写道
而且,一个字符串字面常量总是引用String类的同一个实例。这是因为字符串字面常量,或者更一般的情况,表示常量表达式的值的字符串,被通过使用String.intern方法而“限定”了,这样做是为了让它们可以共享唯一的实例。


综上,相同的字符串字面常量总是引用同一个String实例,这个实例被String.intern方法而“限定”了。

==================================================================================

关于class文件常量池的理解
class文件中的常量池存放的是class文件结构及其子结构中所有的字面常量、类或接口名、字段和方法等。比如对于类中的一个属性的定义语句:
private String name = new String("slevin");


属性“name”及其内容“slevin”都保存在class文件的常量池中
  • 属性名“name”以CONSTANT_Fieldref_info格式存储
  • 内容“slevin”以CONSTANT_String_info格式存储的

注意:虽然“slevin”是String字面常量,但目前还不是引用类型
《Java虚拟机规范SE8》4.4.3节 写道
> CONSTANT_String_info格式包含一个该格式对应的tag,和一个指向CONSTANT_Uft8_info的索引。这个结构表示Unicode码点序列,这个序列最终会初始化成一个String对象

什么时候会“初始化成一个String对象”呢?这就涉及到运行时常量池了。

==================================================================================

关于运行时常量池的理解:
《Java虚拟机规范SE8》5.1节 写道
当类或接口创建时,它的二进制表示中的常量池表(即class文件常量池)被用来构造运行时常量池。运行时常量池最初阶段一部分是符号引用,另一部分得自常量池表中的某些项。


《Java虚拟机规范SE8》5.1节 写道
为了得到字符常量,Java虚拟机需要检查CONSTANT_String_info结构中的码点序列:
  • 如果某String实例所包含的Unicode码点序列与CONSTANT_String_info结构所给出的序列相同,而之前又曾在该实例上面调用过String.intern方法,那么此次字符常量获取的结果将是一个指向相同String实例的引用
  • 否则,会创建一个新的String实例,其中包含由CONSTANT_String_info结构所给出的Unicode码点序列;字符常量获取的结果是指向那个新Strlng实例的引用。最后,新String实例的intern方法被Java虚拟机自动调用

再看以下JDK8中关于String.intern()方法的描述:
JDK8 写道
public String intern()
Returns a canonical representation for the string object.
A pool of strings, initially empty, is maintained privately by the class String.
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.
It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is 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.
Returns:
a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.


所以可以这样理解:

  1. String字面量的值先在编译期间被记录在class文件中的常量池表中
  2. 类被创建时,运行时常量池根据class文件常量池表中的内容,创建String字面量
  3. String字面量是对String类实例的引用,这些实例是被intern过的,存放在堆中;字面量存放在运行时常量池中
  4. 堆中所有intern过的String实例都通过String类管理,所以可以说String池是由String类管理的。


==================================================================================

关于String池的理解:
String池是由String类维护的,位于堆中。对String池中的String实例的引用被存放在运行时常量池中。如果方法中有如下代码:

String name1="slevin";

name1得到的是String池中的一个String对象的引用,该对象的值也是“slevin”

String name2=new String("slevin").intern();

name2得到的是String池中的一个String对象的引用,该对象的值也是“slevin”

我个人认为:
  • name1直接通过运行时常量池得到了池中的“slevin”实例的引用,因为编译时这行代码的操作应该是根据class常量池中该字面量的索引得到值并放入局部变量表。而类在被创建后,class常量池被解析成运行时常量池。
  • name2通过String类维护的String池得到池中的“slevin”实例的引用,尽管这个引用已经放在了运行时常量池中,因为编译时这行代码的操作应该是根据class常量池中该字面量的索引得到值,然后当做参数传给String.intern()方法。

以上两条是我的推测,以后会根据反汇编加以证实。
分享到:
评论

相关推荐

    java入门教程:数据类型_运行时常量池.docx

    运行时常量池是每个类或接口的常量池在JVM运行时的实现,它存在于方法区中。当类被加载时,Class文件中的常量池会被加载到运行时常量池。常量池包含了各种字面量(如字符串、数字)和符号引用(如类和方法的全限定名...

    JVM常量池教程吐血整理干货.md

    与Class常量池不同,运行时常量池是动态的,这意味着它可以随着程序执行过程中的需求变化而扩展。例如,在运行时通过反射机制调用类的方法时,可能会向运行时常量池中添加新的符号引用。 运行时常量池位于方法区,...

    java 内存中 堆、栈、常量池、方法区的总结

    在Java内存管理中,堆(Heap)、栈(Stack)、常量池(Constant Pool)和方法区(Method Area)是四个核心概念,它们在Java程序运行时扮演着不同的角色。 首先,方法区是用来存放类的信息、常量、静态变量等数据的...

    深入理解JVM实战篇-String类1

    本文将探讨String类的一些关键特性,包括字面量与运行时常量池、String的intern()方法以及它们如何影响内存管理。 首先,我们需要理解Java中的字面量和运行时常量池。字面量是源代码中直接出现的值,如"Hello"。在...

    java中常量以及常量池

    1、举例说明 变量 常量 字面量  1 int a=10;  2 float b=1.234f;  3 String c="abc";  4 final long d=10L;  a,b,c为变量,d为常量 两者都是左值;...  运行时常量池:是jvm虚拟机在完成类装

    什么是字符串常量池?Java开发Java经验技巧共6页.p

    字符串常量池是Java虚拟机(JVM)在运行时为字符串常量创建的一个特殊的存储区域,它的主要作用是为了提高内存效率和字符串的复用。 首先,我们来明确一下什么是字符串常量。在Java中,字符串是不可变的对象,一旦...

    java常量池分析.pdf

    Java常量池是Java编程语言中的一个重要概念,它在JVM(Java虚拟机)的运行时数据区中占据着核心地位。常量池是每个类或接口在编译时都会生成的一部分,它存储了各种类型的常量,包括字面量(如字符串、整数、浮点数...

    java内存分配之常量池,栈,堆1

    在运行时,如果两个字符串的值相等,它们在常量池中可能只有一份拷贝,这是Java字符串常量池复用机制的体现。在Java 6及之前,字符串常量池位于永久代,从Java 7开始移到了堆中。 栈和堆之间的区别在于,栈中的数据...

    java技术面试必问:JVM-内存模型讲解.docx

    当类加载到内存后,JVM就会将class文件常量池中的内容存放到运行时常量池中;在解析阶段,JVM会把符号引用替换为直接引用(对象的索引值)。例如:类中的一个字符串常量在class文件中时,存放在class文件常量池中的...

    JVM 50 道面试题及答案.docx

    JVM 中的常量池有三种类型:字符串常量池、运行时常量池和类文件常量池。字符串常量池存放在堆中,包括 String 对象执行 intern() 方法后存放的地方和双引号直接引用的字符串。运行时常量池存放在方法区,属于元空间...

    深入探索Java常量池

    Java常量池是Java虚拟机(JVM)中一个非常重要的概念,它主要分为两种:静态常量池和运行时常量池。静态常量池是class文件中的常量池,包括字符串(数字)字面值、类和方法的信息,占用了class文件的大部分空间。...

    字符数组的存储方式 字符串常量池.docx

    使用`new String()`创建字符串时,无论常量池中是否已有该字符串,JVM都会在堆中创建一个新的String对象。例如: ```java String s1 = new String("11"); String s2 = new String("11"); System.out.println(s1...

    探究Java常量本质及三种常量池(小结)

    而运行时常量池是JVM虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期...

    Java中的String池

    2. **字符串对象池**:通常所说的String池实际上指的是String对象池,它是运行时常量池的一部分。当我们使用`new String("Hello")`创建字符串时,即使字符串字面量已经存在于常量池中,也会创建一个新的String对象。...

    java堆、栈和常量池

    - **结构形式**:在JVM中,常量池是以表的形式存在的。对于String类型,有一张固定的`CONSTANT_String_info`表来存储文字字符串值,该表只存储文字字符串值,而不包含符号引用。 #### 五、总结 Java的内存管理机制...

    JVM内存分配与垃圾回收详解

    本文对 JVM 内存分配与垃圾回收进行了详细的解释,包括 JVM 运行时数据区域、String 常量池、垃圾回收、垃圾收集算法等内容。了解 JVM 内存分配与垃圾回收是 Java 开发者必须掌握的基础知识之一。

Global site tag (gtag.js) - Google Analytics