JVM常量池与String池_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > JVM常量池与String池

JVM常量池与String池

 2018/4/6 15:11:39  slevin1994  程序员俱乐部  我要评论(0)
  • 摘要:内容原创,欢迎指正,转载注明http://slevin1994.iteye.com/blog/2415778字面常量《Java语言规范基于JavaSE8》3.10节写道字面常量是类型为简单类型,String类型和空类型的**值**在源程序中的表示。包括整数字面常量,浮点数字面常量,布尔字面常量,字符字面常量,字符串字面常量和空字面常量。整数字面常量,它的类型是long或者int(基本类型)浮点数字面常量,它的类型是float或者double(基本类型)布尔字面常量,它的类型是boolean
  • 标签: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()方法。

以上两条是我的推测,以后会根据反汇编加以证实。
发表评论
用户名: 匿名