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

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中常量以及常量池

    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常量池,涉及静态常量池和运行时常量池的介绍,常量池的好处,8种基本数据类型的包装类和常量池等相关内容,具有一定参考价值,需要的朋友可以了解下。

    论文研究-基于JVM内存模型的String分析 .pdf

    基于JVM内存模型的String分析,王培,程明,本文首先介绍了运行时的Java程序的内存管理模型中的方法区、堆和Java栈等几块内存区域,又介绍了存于堆中的常量池这块比较特殊的内�

    Java进阶教程解密JVM视频教程

    学习字节码指令的的运行流程,字节码指令与常量池、方法区的关系。掌握条件分支、循环控制、异常处理、构造方法在字节码级别的实现原理,利用HSDB工具理解多态原理。还会涉及从编译期的语法糖处理,到类加载的各个...

    jdk-12_osx-x64_bin.tar.gz

    引入 API 对关键类文件和运行时工件建模,特别是可从常量池加载的常量。在新的 java.lang.invoke.constant 包中定义了一系列基于值的符号引用(JVMS 5.1)类型,它们能够描述每种可加载常量。符号引用以纯 nominal ...

    java8源码-jvm-study:jvm-study

    java8 源码 jvm-study 方法执行过程 ...初始化运行时数据区 方法区:存放 class;静态变量:常量 堆:实例对象 栈:栈帧(对象的引用,方法) 类加载 执行方法 创建对象 堆空间分代划分 outOfMemory异常 ...

    深入Java虚拟机(原书第2版).pdf【附光盘内容】

    2.3.4 非标准运行时库 2.3.5 对虚拟机的依赖 2.3.6 对用户界面的依赖 2.3.7 java平台实现中的bug 2.3.8 测试 2.4 平台无关的七个步骤 2.5 平台无关性的策略 2.6 平台无关性和网络移动对象 2.7...

    个人对JVM五大部分的总结(欢迎网友指点、补充、指出错误)

    要是Eden放不下,就会触发Minor GC垃圾回收,新生代使用的GC算法为引用计数法,首先Eden中存活的对象(仍然有在程序运行中被引用,这个引用可能是Method方法区中的常量池存储的引用【String引用、或者非浮点数的引用...

    java 面试题 总结

    Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。 与cgi的区别...

    java面试题

    答:运行时异常时(JVM)java虚拟机在运行过程中发生的问题,比如:内存溢出等问题。这类异常没法要求程序员去一一捕获并抛出,一般异常是Java类库或程序员自己写的代码发生的错误,这类异常可以由我们去一一捕获并...

    超级有影响力霸气的Java面试题大全文档

     Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。 与cgi的区别...

    AIC的Java课程1-6章

     [*]了解Java内存机制:栈、堆、常量池等,理解垃圾回收机制。 第3章 面向过程(数组和方法) 4课时  理解如何声明数组、构造数组、初始化数组以及使用数组中的各个元素。  清楚数组作为...

    Java范例开发大全 (源程序)

     实例11 常量与变量 18  实例12 各种进制的转换 19  实例13 Java中的进制与移位运算符 22  第3章 条件控制语句(教学视频:75分钟) 26  3.1 if控制语句 26  实例14 判断输入的年份是否为闰年 26  实例...

    java范例开发大全(pdf&源码)

    实例11 常量与变量 18 实例12 各种进制的转换 19 实例13 Java中的进制与移位运算符 22 第3章 条件控制语句(教学视频:75分钟) 26 3.1 if控制语句 26 实例14 判断输入的年份是否为闰年 26 实例15 抽奖活动 27 3.2 ...

    java范例开发大全源代码

     实例11 常量与变量 18  实例12 各种进制的转换 19  实例13 Java中的进制与移位运算符 22  第3章 条件控制语句(教学视频:75分钟) 26  3.1 if控制语句 26  实例14 判断输入的年份是否为闰年 26 ...

    java范例开发大全

    实例11 常量与变量 18 实例12 各种进制的转换 19 实例13 Java中的进制与移位运算符 22 第3章 条件控制语句(教学视频:75分钟) 26 3.1 if控制语句 26 实例14 判断输入的年份是否为闰年 26 实例15 抽奖活动 27 3.2 ...

    Java范例开发大全(全书源程序)

    实例11 常量与变量 18 实例12 各种进制的转换 19 实例13 Java中的进制与移位运算符 22 第3章 条件控制语句(教学视频:75分钟) 26 3.1 if控制语句 26 实例14 判断输入的年份是否为闰年 26 实例15 抽奖活动 ...

Global site tag (gtag.js) - Google Analytics