关于String的intern()方法细节

  String.intern()是一个Native方法,底层调用C++的 StringTable::intern方法实现。当通过语句str.intern()调用intern()方法后,JVM 就会在当前类的常量池中查找是否存在与str等值的String,若存在则,直接返回常量池中相应Strnig的引用;若不存在,则会复制该对象的引用,放入常量池中,然后返回这个String在常量池中的引用。因此,只要是等值的String对象,使用intern()方法返回的都是常量池中同一个String引用,所以,这些等值的String对象通过intern()后使用==是可以匹配的。

 

 public void test1() {
        String s1 = new String("1") + new String("1");
        s1.intern();
        String s2 = "11";
        System.out.println("s1 == s2:"+(s1 == s2));
    }

运行截图:

该结果是在jdk8中运行的结果,jdk7及以上版本运行结果基本一致,只有jdk7之前的版本结果会不一致。这是因为在jdk7之前的版本,字符串常量池存储在方法区中,而到了jdk7以后,字符串常量池被移到了堆内存中,所以会有变化。

首先,在执行String s1 = new String("1") + new String("1")的时候,他会在堆中new一个StringBuilder的新对象sb,然后在new一个String的新对象str1,接着在字符串常量池中找有没有”1“这个字符串,没有的话就会在字符串常量池创建一个”1“的·字符串,然后把”1“传给String对象str1,然后执行sb.append(str1),同理,接着new一个String的新对象str2,接着执行sb.append(),执行完所有的append()后,调用sb.toString()方法,返回一个新String对象。所以,执行完这个过程后,在堆中就有”11“字符串的对象,在字符串常量池中有”1“字符串。

然后执行s1.intern();这个过程会在字符串常量池寻找有没有”11“这个字符串,如果存在,则直接将该引用返回给他,没有的话,会复制该对象的引用,放入常量池中,所以在字符串常量池中就有了一个指向”11“对象的引用。

接着执行 String s2 = "11"语句,他会在常量池中找有没有”11“的字符串,而第二条语句就有一个指向”11“对象的字符串,所以把这个引用赋值给s2。

所以,s1和s2指向的地址是一样的,因此s1 == s2 结果为true。

下面我们再来看一个例子,将上面  String s2 = "11"的语句放在语句 s1.intern()的前面,如下

public void test2() {
        String s1 = new String("1") + new String("1");
        String s2 = "11";
        s1.intern();
        System.out.println("s1 == s2:"+(s1 == s2));
    }

运行截图:

由结果可以看出,对换位置后结果却是相反的,这是为什么呢?

首先,在执行String s1 = new String("1") + new String("1")的时候,他会在堆中new一个StringBuilder的新对象sb,然后在new一个String的新对象str1,接着在字符串常量池中找有没有”1“这个字符串,没有的话就会在字符串常量池创建一个”1“的·字符串,然后把”1“传给String对象str1,然后执行sb.append(str1),同理,接着new一个String的新对象str2,接着执行sb.append(),执行完所有的append()后,调用sb.toString()方法,返回一个新String对象。所以,执行完这个过程后,在堆中就有”11“字符串的对象,在字符串常量池中有”1“字符串。

接着执行String s2 = "11";这个过程会在字符串常量池找有没有相同的值,有则返回他的引用,没有的话就在字符串常量池创建。所以,执行完String s2 = "11"之后,字符串常量池就存在”11“这个字符串了,接着执行s1.intern();这个过程会在字符串常量池寻找有没有”11“这个字符串,显然,前一条语句执行后就有了,所以直接返回给他。

根据分析可以看出s1的字符串地址是指向堆中的,而s2是指向字符串常量池中的。所以s1 == s2 结果为false(注意,我们前面说到从jdk7以后,字符串常量池移到了堆中,所以我们这里所说的在堆中指的是不在字符串常量池的另一块区域)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值