intern

1
2
3
4
5
String str1 = new StringBuilder("ni ").append("hao").toString();
System.out.println(str1.intern() == str1);

String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2);

这段代码在jdk1.6中运行,会得到两个false,而在jdk1.7中运行会得到一个true一个false。产生差异的原因是:在jdk1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串实例的引用,而用StringBuilder创建的字符串实例在Java堆上,所以必然不是同一个引用,将返回false。而jdk1.7中的intern()实现不会再复制实例,只是在常量池中记录首次出现的实例引用,因此intern()返回的引用和由StringBuilder创建的那个字符串实例是同一个。对str2比较返回false是因为“java”这个字符串在执行StringBuilder.toString()之前已经出现过,字符串常量池中已经有它的引用了,不符合首次出现的原则,而“ni hao”这个字符串则是首次出现的,因此返回true。

1
2
3
4
5
6
String s1 = "Programming";
String s2 = new String("Programming");
String s3 = "Program" + "ming";
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1 == s1.intern());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//s1常量池中
String s1 = "ab123" ;
//s2在堆中
String s2 = new String( "ab123" ) ;
System.out.println( s1 == s2 );
//s3到常量池中取s1的引用
String s3 = s2.intern() ;
System.out.println( s1 == s3 ) ;
//而s2在堆中,并没有在常量池中
System.out.println(s2 == s3);

//new会创建两个对象,两个1在堆上,而另两个1在常量池中,
// intern指向常量池,寻找11并没有,就在常量池中新建11,s4就指向s6,而s6==s5
String s5 = new String("1") + new String("1");
s5.intern();
String s4 = "11";
System.out.println(s5 == s4);

//new会创建两个对象,一个9在堆上,而另一个在常量池中,
// intern指向常量池,并没有在常量池中新建9,ss指向常量池,
String s = new String("9");
s.intern();
String ss = "9";
//s在堆上,而ss在常量池中
System.out.println(s == ss);