谈谈String.intern方法

谈谈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. (1)中创建了两个对象:
    我们使用JClasslib插件查看一下字节码文件:
    在这里插入图片描述
    1 、在堆空间中new出来的 new String();
    2 、字符串常量池中的“ab”;

  2. (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()方法!

  1. 我们直接来看一道面试题
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!
最后附两张图:
在这里插入图片描述
在这里插入图片描述

  • 26
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值