在《深入理解
Java
虚拟机》书中,提到在jdk1.7
版本中用String.intern()
返回引用
public class TestAutoFixed {
public static void main(String[] args) {
String str1=new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern()==str1);
String str2=new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern()==str2);
}
}
运行结果: true false,产生结果如下解释
JDK 1.7
(以及部分其他虚拟机,例如JRockit
)的intern()
实现不会再复制实例,只是在常量池中记录首次出现的实例引用,因此intern()
返回的引用和由StringBuilder
创建的那个字符串实例是同一个。
对str2
返回false
是因为“java”
这个字符串在执StringBuilder.toString()
之前已经出现过,字符串常量池中已经有它的引用了,不符合“首次出现”的原则,而“计算机软件”这个字符串则是首次出现的,因此返回true。
现在的疑问是“java”
这个字符串在常量池中什么时候存在了?
我最开始的猜想是“java”
这个字符串是不是常驻在常量池中的?
从网上百度了些资料发现是java
虚拟机会自动调用System
类
public final class System {
/**
* Initialize the system class. Called after thread initialization.
*/
private static void initializeSystemClass() {
//...
sun.misc.Version.init();
//...
}
}
public class Version {
private static final String launcher_name = "java";
private static final String java_version = "1.8.0_202";
private static final String java_runtime_name = "Java(TM) SE Runtime Environment";
private static final String java_profile_name = "";
private static final String java_runtime_version = "1.8.0_202-b08";
}
看到常量池在运行时,已经自动加入了“java”
字符串,所以常量池中已经有了“java”
字符串。
public class TestAutoFixed {
public static void main(String[] args) {
String str1=new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern()==str1);
String str3 = new StringBuilder("计算机软").append("件").toString();
System.out.println(str3.intern()==str3);
}
}
true
false
第一个返回true是因为我们计算机软件
首次出现,满足jdk1.7之后的首次遇到原则
(jdk1.7包括及以上字符串分配在堆上,不会再复制一份实例到常量池中,而是直接指向首次出现的地址引用),所以第一个返回true指向同一个对象,第二个因为不满足首次遇到原则
,所以返回false