谈谈String.intern方法
1. 首先明确什么是intern()方法?
String.intern()是一个Native方法,底层调用C++的 StringTable::intern方法实现。当通过语句str.intern()调用intern()方法后,JVM 就会在当前类的常量池中查找是否存在与str等值的String,若存在,则直接返回常量池中相应Strnig的引用;若不存在,则会在常量池中创建一个等值的String,然后返回这个String在常量池中的引用。
2. intern()方法在jdk6和jdk(7/8)的区别
(1)在jdk6中,字符串常量池在永久代,调用intern()方法时,若常量池中不存在等值的字符串,JVM就会在字符串常量池中创建一个等值的字符串,然后返回该字符串的引用;
(2)在jdk7/8中,字符串常量池被移到了堆空间中,调用intern()方法时,如果常量池已经存在该字符串,则直接返回字符串引用,否则复制该堆空间中字符串对象到常量池中并返回。
3. 明白了上述,然后我们先来看一段代码
public class StringNewTest {
public static void main(String[] args) {
(1) String str = new String("ab");
(2)String str = new String("a") + new String("b");
}
}
4.回答问题
(1)中代码执行的过程中创建了几个对象?
(2)中代码执行的过程中创建了几个对象?
-
(1)中创建了两个对象:
我们使用JClasslib插件查看一下字节码文件:
1 、在堆空间中new出来的 new String();
2 、字符串常量池中的“ab”; -
(2)中创建了六个对象:
1 、new StringBuilder(); 因为是字符串的拼接操作
2 、new String(“a”);
3 、字符串常量池中的“a”;
4 、new String(“b”);
5 、字符串常量池中的“b”;
6 、StringBuilder中的toString方法里的 new String(char[]);
我们查看一下toString()方法的字节码文件:
注意:整个字节码文件都没有显示,字符串常量池中存在"ab"!
在明白了new String()到底创建了几个对象之后,我们再来看String.intern()方法!
- 我们直接来看一道面试题
public class StringInter {
public static void main(String[] args) {
String s = new String("1");
s.intern();
String s2 ="1";
(1) System.out.println(s == s2);//
String s3 = new String("1") + new String("1");
s3.intern();
String s4 = "11";
(2) System.out.println(s3 == s4);//
}
}
1 、在jdk6中,结果为 false false
原因:
(1)执行完第一行代码,会创建两个对象:堆空间的new String ()和字符串常量池(jdk6中字符串常量池在永久代)中的“1”;这个时候字符串常量池中是存在“1”的;所以执行 s.intern();直接返回“1”的引用。执行 String s2 =“1”;由于常量池中已经存在“1”,所以s2直接指向常量池中“1”的引用 !
所以,s2的地址是字符串常量池中的“1”,s的地址在堆空间,二者并不相等!结果为false
(2)上面分析过,s3存在于堆空间中,由于在jdk6中字符串常量池在永久代中,执行s3.intern()时,相当于创建了一个新的对象”11“,所以产生新地址!s4则是在字符串常量池中,所以s3、s4并不相等,结果为false!
2 、在jdk7/8中,结果为false true
原因:
(1)在jdk7/8中除了字符串常量池的位置不一样,false的原因和jdk6一样
(2)这是一个字符串拼接操作,上文已经分析过,执行完第一行代码,会创建6个对象,但是这个“11”是存在于堆空间中的,字符串常量池中并没有“11‘,然后执行 s3.intern();在jdk7/8中,字符串常量池移到了堆空间中,为了节省空间,优化内存,他会创建一个指向堆空间中new String(“11”)的地址。所以执行完 s3.intern();此时的字符串常量池中的”11“是引用堆空间的new String(“11”)的地址。 当执行String s4 = "11"时, s4会从常量池中找到”引用地址“,所以这样看来,s4 指向”引用地址“,”引用地址“指向堆空间中的new String(“11”),而s3本来就指向堆空间中的new String(“11”),二者相等,结果为true!
最后附两张图: