http://blog.csdn.net/u010297957/article/details/50995869
概念:
1、常量池表(constant_pool table)
Class文件中存储所有常量(包括字符串)的table
这是Class文件中的内容,还不是运行时的内容,不要理解它是个池子,其实就是Class文件中的字节码指令.
2、运行时常量池(Runtime Constant Pool)
JVM内存中方法区的一部分,这是运行时的内容
这部分内容(绝大部分)是随着JVM运行时候,从常量池转化而来,每个Class对应一个运行时常量池
2中说绝大部分是因为:除了 Class中常量池内容,还可能包括动态生成并加入这里的内容
3. 字符串常量池(String Pool)
这部分也在方法区中,但与Runtime Constant Pool不是一个概念,String Pool是JVM实例全局共享的,全局只有一个
JVM规范要求进入这里的String实例叫“被驻留的interned string”,各个JVM可以有不同的实现,HotSpot是设置了一个哈希表StringTable来引用堆中的字符串实例,被引用就是被驻留
(JDK1.6字符串常量池在方法区中存储,JDK1.7中放在了堆。(不知道正确性在一个ppt中看到的,不过和上面这句话形容的一样。))
这里的使用了一种设计模式:享元模式。也就是说:一个系统中如果有多处用到了相同的一个元素,那么我们应该只存储一份此元素,而让所有地方都引用这一个元素。
. 描述
我觉的好像前面1和2随便说了点概念,就好像快说完了……
那么,来个Example吧!在*.java文件中有如下代码:
int a = 1;String b = "asd";
-
首先,
1
和"asd"
会在经过javac(或者其他编译器)编译过后变为Class文件中constant_pool table
的内容 -
当我们的程序运行时,也就是说JVM运行时,每个Class
constant_pool table
中的内容会被加载到JVM内存中的方法区中各自Class的Runtime Constant Pool
-
一个没有被
String Pool
包含的Runtime Constant Pool
中的字符串(这里是"asd"
)会被加入到String Pool
中(HosSpot使用hashtable引用方式),步骤如下:- 在Java Heap中根据
"asd"
字面量create
一个字符串对象 - 将字面量
"asd"
与字符串对象的引用在hashtable中关联起来,键 - 值 形式是:"asd"
=对象的引用地址
- 在Java Heap中根据
另外来说,当一个新的字符串出现在Runtime Constant Pool
中时怎么判断需不需要在Java Heap中创建新对象呢?
策略是这样:会先去根据equals来比较Runtime Constant Pool
中的这个字符串是否和String Pool
中某一个是相等的(也就是找是否已经存在),如果有那么就不创建,直接使用其引用;反之,如上3
如此,就实现了享元模式,提高的内存利用效率
2. 例子
上面的描述其实对于能看到这篇文章的程序员们来说很好懂,下面我们来找一些面试题练练手吧
1. String s = new String(“abc”) 创建了几个对象?
答:
2个
解析:
-
首先,出现了字面量
"abc"
,那么去String Pool
中查找是否有相同字符串存在,因为程序就这一行代码所以肯定没有,那么就在Java Heap中用字面量"abc"
首先创建1个String对象 -
接着,
new String("abc")
,关键字new又在Java Heap中创建了1个对象,然后调用接收String参数的构造器进行了初始化。最终s
的引用是这个String对象如上:2个
2. 下面程序的输出?
public static void main(String[] args) { String s1 = "abc"; String s2 = new String("abc"); String s3 = "a" + "bc"; System.out.println(s1 == s2); System.out.println(s1 == s3); System.out.println(s1 == s1.intern());}
答:
System.out.println(s1 == s2);//flaseSystem.out.println(s1 == s3);//trueSystem.out.println(s1 == s1.intern());//true
解析
-
首先,根据题1所述,这里同理,s1和s2肯定不是一个引用;
-
其次
String s3 = "a" + "bc";
这行代码最终是"abc"
,根据s1,它已经在String pool
中了,所以s3和s1是引用的同一个对象; -
最后,s1.intern()方法:将某个String对象在运行期动态的加入
所以,还是会返回和s1同一个对象的引用,所以true;String pool
(如果pool中已经有一个了就不加)并返回String pool
中保证唯一的一个字符串对象的引用。