String类中的intern()方法是手动把String对象加入到字符串常量池中
先来看一个简单的代码:
示例1:
@Test
public void test1(){//测试通过
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
Assert.assertTrue(str1 == str2);
}
第一句:首先在堆中创建对象"hello"
,也会在常量池中创建"hello"
,intern()方法则检查常量池中 是否含有"hello",结果发现常量池中含有,则返回常量池中"hello"的地址
第二句:指向常量池中"hello"对象
结果:str1指向常量池中的“hello”对象,str2指向常量池中的“hello”对象
实例二
@Test
public void test2(){//测试不通过
String s1 = new String ("hello");
String s2 = s1.intern();
Assert.assertTrue(s1==s2);
}
第一句:堆中创建了"hello",也会在常量池创建"hello"
第二句:intern()会去常量池检查是否存在"hello",结果发现存在,则此时返回常量池的引用地址给s2
第三句:此时s1指向堆中"hello",s2指向常量池"hello"
示例三
@Test
public void test3(){ //测试不通过
String s1 = new String("hel") + new String("lo");
String s2 = "hello";
s1.intern();
Assert.assertTrue(s1==s2);
}
第一句:在堆中创建了三个对象,分别是"hello",“lo”,拼接之后产生"hello",也会在常量池中创建"hel",“lo”
第二句:在常量池中创建"hello",此时常量池中含有"hel",“lo”,“hello”
第三句:检查常量池是否有"hello",结果发现有了,此时应该返回常量池"hello"的地址,但是并没有变量去接收这个返回值,所以在这里这一句没什么用
第四句:s1指向堆中"hello",S2指向常量池"hello"
示例四
@Test
public void test4(){//测试通过
String s1 = new String("hel") + new String("lo");
s1.intern();
String s2 = "hello";
Assert.assertTrue(s1==s2);
}
第一句:在堆中创建了三个对象,分别是"hello",“lo”,拼接之后产生"hello",也会在常量池中创建"hel",“lo”
第二句:检查到"hello"不在常量池中,如果在jdk1.6就将"hello"添加到常量池中,如果是jdk1.7,则在常量池中保存堆中对象的引用,也就是地址
第三句:检查到常量池有一个地址保存了"hello"对象的引用,则s2就直接指向"hello"这个字符串地址,也就是是堆中的"hello"
第四句:s1指向堆中的“hello”,s2指向堆中“hello”
实例5
@Test
public void test3(){//测试通过
String s1 = new String("hel") + new String("lo");
String s2 = "hello";
Assert.assertTrue(s2==s1.intern());
}
第一句:在堆中创建了三个对象,分别是"hello",“lo”,拼接之后产生"hello",也会在常量池中创建"hel",“lo”
第二句:创建常量池中的对象“hello”
第三句:检查常量池中是否有“hello”这个对象,结果发现有了,则返回常量池中的对象引用
结果:s3指向常量池中的对象,s1指向常量池中的对象
在jdk1.6及以下版本和jdk1.7及以上版本
对intern方法调用会存在差异,在jdk1.6中,,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用。否则,将此字符串实例复制到字符串常量池中,并且返回该字符串的引用
但是在jdk1.7中,当调用intern()方法时,如果字符串常量池先前已创建出该字符串对象,则返回池中的该字符串的引用,只是会把字符串实例的引用添加到常量池中,并返回此引用;