String.intern()方法与常量池存入时的疑惑!

环境

jdk:1.8

今天再看极客学院关于《JVM自动内存管理:内存区域基础概念》
有这么一块没有看懂:

public class RuntimeConstantPoolChange {

    public static void main(String[] args) {
        // 第一段代码
        String str1 = new StringBuilder("极客").append("学院").toString();
        System.out.println(str1.intern() == str1);
        // 第二段代码
        String str2 = new StringBuilder("极客").toString();
        System.out.println(str2.intern() == str2);
    }
}

结果:

true
false

这段代码中的str2是着实没有看懂为什么为false。

经过在网上查阅各种博客后,终于明白了,以此记录下。

我们先看第一段代码:

String str1 = new StringBuilder("极客").append("学院").toString();
System.out.println(str1.intern() == str1);

我们先看第一段代码
①因为极客学院,是用双引号声明,所以会在常量池中创建两个相应的字符串对象。
②由于使用new,所以会在java heap(堆)中创建一个内容为极客学院的字符串对象(暂时命名为s1,方便后面使用),并返回在堆中的引用。

当调用str1.intern()的时候,第一步会去常量池中去找是否有极客学院的字符串。要是没有,则就在常量池中记录Java Heap中首次出现的该字符串的引用,并返回该引用。

也就是说这时常量池中保存的引用是我们之前在java heap(堆)中创建的那个s1。所以实际效果为s1 == str1,这里的s1就是str1,这也就是为什么str1.intern()==str1为true的原因。

我们再来看第二段:

String str2 = new StringBuilder("极客").toString();
System.out.println(str2.intern() == str2);

首先同样是:
①由于字符串极客使用双引号声明。所以会去常量池中看是否已经存在(若不存在,则创建一个字符串对象),由于在第一段代码中已经存在了,所以这时什么也不会干。

②又由于使用new ,所以会在java heap(堆)中创建一个内容相同的String对象。然后返回堆中String对象的引用。

也就是说第二段代码分别在常量池和堆中生成了两个内容相同的String对象。
(由于第一段代码中已经创建过了,所以这里只会有在堆中创建String对象的操作)

再执行str2.intern() == str2时,str2.intern()返回的是第一段代码s1的引用。实际效果是str1 == str2,这肯定会返回false,因为str1和str2只是内容相同在堆中new出来的两个String对象。其引用肯定是不同的!

String.intern方法

概述

String.intern()是一个Native方法,它的作用是:如果运行时常量池中已经包含一个等于此String对象内容的字符串,则返回常量池中该字符串的引用;如果没有,则在常量池中创建与此String内容相同的字符串,并返回常量池中创建的字符串的引用。

JDK1.7改变

当常量池中没有该字符串时,JDK7的intern()方法的实现不再是在常量池中创建与此String内容相同的字符串,而改为在常量池中记录Java Heap中首次出现的该字符串的引用,并返回该引用。

参考链接:
String放入运行时常量池的时机与String.intern()方法解惑
由常量池 运行时常量池 String intern方法想到的(三)之String内存模型
由常量池 运行时常量池 String intern方法想到的(四)之深入理解intern
深入解析String#intern 及其可能带来的问题

你可能感兴趣的:(Java)