String的intern方法在jdk1.7以后发生了改变,主要区别如下
1. jdk1.6的版本,先查找常量池中有无相同字符串的引用,若有,则返回该字符串对象,若无,则拷贝字符串对象到常量池中,返回常量池的对象
2.jdk1.7以后的版本中,字符串在常量池的存在不再是字符串对象,而是一个指向堆的引用。具体为:
(1)执行intern时,如果字符串没有出现过,则在常量池记录首次出现的该字符串的实例的引用
(2)如果出现过,则返回实例的引用
在判断字符串对象是否统一对象中,除了以上的特性,还必须清楚
1.已确定的字符串在编译器就已经在常量池存在引用
2.java等特殊的字符串在某些时刻已经被加载到常量池中
以下为String的测试代码,代码结果的解释在注释中备注
String str1 = new String("ABC"); // 创建了一个新的对象
String str2 = "ABC"; // 从常量池查找ABC若有则返回常量池中的引用,若不存在则在常量池生成一个ABC,返回引用
System.out.println( str1 == str2); // 为false,因为str2是常量池的引用,str1是在堆中新建的引用
System.out.println( str1.intern() == str2); // 为true, str1.intern 先去常量池查找有无字符串,有则返回了引用,与str2一致
str1 = new String("计算机");
// 确定的字符串在编译器就已经在常量池存在引用
System.out.println( str1.intern() == str1); // 为false,
// 因为“计算器”字符在编译阶段就创建到常量池了,常量池的地址与java堆中new出来的地址肯定不同
str1 = new StringBuilder().append("中").append("国").toString();
// StringBuilder 创建了字符串,
// str1.intern 先去常量池查找有无字符串,
// 若无,jdk1.6会拷贝字符串到常量池中,返回常量池到引用,
// jdk1.7以上会将首次出现字符串到引用放到常量池中,返回常量池到地址
System.out.println(str1.intern() == str1); // true// 在jdk1.6中是false
str1 = "ja"+"va";
// str1 在编译阶段就知道是java了,在常量池中,str1
System.out.println(str1.intern() == str1); // true
String s1 = "abc";
String s4 = "a" + "bc";
System.out.println("测试编译阶段字符串+的结果," + (s1 == s4));
str1 = new StringBuilder().append("ja").append("va").toString();
System.out.println(str1.intern() == str1); // false ,
// java 字符串在某个时刻已经被加载到常量池中,str1.intern 返回了首次出现java到实例引用,与str1的对象不同