Java有三种常量池,即字符串常量池、class文件常量池、运行时常量池。
Class常量池:保存类编译生成的字面量和符号引用。Class文件除了类字段,方法,接口描述等,还有Class常量池
运行时常量池: 是JVM的概念,除了存放编译生成字面量和符号引用。还允许运行时产生常量,比如String.intern
方法
字符串常量池。String
类管理的常量池,处于堆内存中。
1. 字符串常量池——特殊的常量池,存在于方法区(method are), 不是堆
字符串常量池在每个VM中只有一份,他在内存中的位置如图,红色箭头所指向的区域 Interned Strings, 存在于方法区, 不是堆
抽象图
String str1 = “abc”;
String str2 = “abc”;
String str3 = “abc”;
//new 一定会新建对象——且会有类似引用变量的指向常量池的"引用"行为
String str4 = new String(“abc”);
String str5 = new String(“abc”);
面试题: 相信绝对是个经典兼考倒一堆人的题目
1. String a = new String("1"+"2")共建了几个对象?
2个
第一个:看构造器里面("1"+"2"),这个是在编译期就已经做了处理,即代表生成一个字符串:"12"
第二个:当使用new的方法创建字符串时,注意这个”new“,就表示直接开辟了内存空间;然后把值"引用”的常量池中的“12”。最后返回该对象引用。
所以就创建了2个对象。
总结:
1. string的 "+操作符,先在常量池生成常量!!” 但是"+"操作符,有编译器优化
2. 有new String(...)的话: String也是常量池生成完之后!!才轮到堆;没有new,就不管堆的情况
2. 同理:String str="a"+"b"+"c" 共建了几个对象?
只有1个
在编译期已经常量折叠为"abc", 通过编译器优化后,得到的效果是
String str="abc"
3. String str2 = new String("ABC") + "ABC" ; 会创建多少个对象?
3个
new String("ABC") :常量池+堆各一个,2个
后面再 "+ ABC": 常量池新生成 “ABCABC" 1个
所以共3个
下面两个池都在方法区里(method area),是每个被加载的类,都有的
2. 运行时常量池(runtime constant pool)
当程序运行到某个类时,class文件中的信息就会被解析到内存的方法区里的运行时常量池中。看图可清晰感知到每一个类被加载进来都会产生一个运行时常量池,由此可知,每个类都有一个运行时常量池。
3. class文件常量池(class constant pool)
class常量池也是在编译后每个class文件都有的
class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是 常量池(constant pool table),用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)。
*字面量就是我们所说的常量概念,如文本字符串、被声明为final的常量值等。
*他在class文件中的位置如上图所示,Constant Pool 中。