常量池
Java虚拟机管理的内存包含以下几个运行时数据区域
方法区与java堆一样,是各个线程共享的内存区域,用于存储已经被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
JDK8之前很多人叫它永久代(这里可以联想下年前代,老年代),是因为当时HotSpot虚拟机的设计团队选择将收集器的分代设计扩展至方法区,或者说使用永久代来实现方法区而已。
这样使得HotSpot的垃圾收集器能像管理Java堆一样管理这部分内存。但是对于其他虚拟机实现是不存在这个概念的。
运行时常量池(Runtime ConstantPool)是方法区的一部分。
Class文件中除了有类的版本、字、方法、接口等描述信息外,还有一项信息是常量池表(ConstantPoolTable),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
String str = “think123” 其中的think123就直接保存在常量池中
运行时常量池存了在编译器能产生之外,在运行期间也可以将新的常量放入池中,这种特性被利用最多的就是String类的intern()方法。
String::intern()
是一个本地方法,它的作用是如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象的引用
否则,会将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
伪代码类似如下:
if(StringPool.contains(search_string)) {
return search_string_addr;
}
search_string_addr = StringPool.add(search_string);
return search_string_addr;
神奇的代码
下面的代码你猜猜会输出什么?
public class Main {
public static void main(String[] args) {
String s1 = new StringBuilder().append("think").append("123").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder().append("ja").append("va"