简介
String.intern()方法是一种手动将字符串加入常量池中的native方法,在此我将其方法分为jdk6和jdk8版本,原理如下:
jdk6:调用该方法时,如果常量池中有该字符串,则返回该字符串(可以理解为String的value指向常量池该常量),如果常量池中没有,则会去堆中查找等价的String对象,并且将它复制到常量池中。
jdk8:调用该方法时,如果常量池中有该字符串,则返回该字符串(可以理解为String的value指向常量池该常量),如果常量池中没有,则会去堆中查找等价的String对象,并且将该对象的引用复制到常量池中。
实例
代码
话不多说,上代码!!!
@Test
public void test(){
String s = new String("2");
s.intern();
String s2 = "2";
System.out.println(s == s2);
String s = new String("3") + new String("3");
s.intern();
String s2 = "33"
System.out.println(s == s2);
}
运行结果
// 请忽略jdk6、jdk8以及空行 为了美观
jdk6:
false
false
-------------------------------------------------------
jdk8:
false
true
解析:
jdk6:
首先new String会生成两个对象 一个存放在常量池,一个存放在堆。我们知道,new对象,引用是指向堆中的。接着我们调用了s.intern(),因为常量池已经存在"2"这一字符,所以会返回常量池中该字符的地址。但是这里我们没有设置一个变量去接收,所以s还是指向堆区。然后我们用一个变量s2等于"2",因为"2"已经在常量池中存在,所以直接返回常量池中"2"的地址。即s指向堆,s2指向常量池。所以为false。
我们来看第二段代码:这里用s = new String("3") + new String("3");实质是StringBuilder来调用append方法。这段代码会在堆区生成"33"这一字符对象,还会在常量池中生成"3"这一字符串常量。然后我们调用了s.intern()方法,由于现在常量池中没有"33"这一常量,所以会从堆中复制过来,同样的,这里我们没有用一个变量去接收,所以s还是指向堆区(如果我们用s去接收,那么s会指向常量池中的"33")。接着我们用s2 = "33",这里就是使s2指向常量池中的"33",所以也为false。
jdk8:
同样我们也来分析这两段代码。首先第一行代码会在堆区生成对象,也会在常量池中生成常量。
我们调用s.intern(),因为常量池中已经存在,所以并没有什么改变。s还是指向堆区。接着你们也知道了,s2指向常量池,固为false。
第二段代码:第一行代码跟上面一样,会在堆区生成"33"字符串对象,常量池生成"3"字符常量,且s指向堆区。当调用s.intern(),由于常量池中没有"33"字符串常量,所以会去堆区查找,查找到了,复制该对象的引用到常量池,你没有看错,就是引用!!!也就是说常量池的"33"存储的是指向堆区"33"的引用。然后s2 = "33",即s2指向常量池"33"字符串常量,而常量池的字符串常量又存储的是指向堆区"33"字符串对象,所以可以理解为s2指向堆区!!!所以就为true!
结束
首先这篇文章是我自己复习八股文时疑惑的地方,权当记录一下。这也是我在查看了许多大佬博客之后自己理解总结的,希望对大家有帮助,如果哪里有错误,请告诉我,谢谢!