关于intern和字符串

来源:互联网 发布:mpu6050单片机电路图 编辑:程序博客网 时间:2024/05/01 16:35

以下实验基于jdk1.8
内容探讨涉及具体JVM的均基于HotSpot VM

首先来看个例子

        String s1 = new String("aa")+new String("a");        String s2 = "aaa";        System.out.println(s1 == s2);

这段代码大家都知道输出是false。但是我们加一行代码来试试看。

        String s1 = new String("aa")+new String("a");        s1.intern();        String s2 = "aaa";        System.out.println(s1 == s2);

这回输出的是true,这是怎么回事?先别急着求答案,我们再改一下代码。

        String s1 = new String("aaa");        s1.intern();        String s2 = "aaa";        System.out.println(s1 == s2);

这回代码的输出呢?答案是false。
这引申出了两个问题

intern的作用是什么?
new String(“aaa”)和new String(“aa”)+new String(“a”)的区别?

其实这两个问题要一起解答。
intern的作用,doc里面是这么描述的:

When the intern method is invoked, if the pool already contains a
string equal to this {@code String} object as determined by
the {@link #equals(Object)} method, then the string from the pool is
returned. Otherwise, this {@code String} object is added to the
pool and a reference to this {@code String} object is returned.

有两个要点,第一,intern从一个pool里面查找,有则返回引用,无则添加;第二,判断String是否一致的方法是equals方法。
pool是什么?全局字符串常量池。注意这里只是保存字符串的引用。也就是说这个字符串可能在java heap里面也有可能在其他的地方,这里只是保存了引用。第二点,intern判断字符串是否相同用的是equals,即如果两个字符串的内容相同那就认为相等。

再搞清楚一个问题,字面量像”aaa”,”aa”,”a”会不会进入字符串常量池,什么时候进入字符串常量池。
关于这个问题的答案参考
Java 中new String(“字面量”) 中 “字面量” 是何时进入字符串常量池的?
简单概括的话就是,字面量是lazy resolve的。所以像new String(“aaa”)中的”aaa”不是在类加载的时候放进常量池的,而是创建的String实例的时候。

        String s1 = new String("aaa");        String s2 = new String("aa") + new String("a");

所以这两行代码的区别在于,第一行将堆中的”aaa”的引用放进字符串常量池,第二行将堆中的”aa”与”a”的引用放进字符串常量池。

        String s1 = new String("aa") + new String("a");        s1.intern();

而上面这两行堆中的”aaa”,”aa”与”a”的引用放进字符串常量池。

还有一个要注意的点是,当程序中直接使用字面量时,会先从字符串常量池中查找,如果有则直接返回引用。

到这里这个问题算是解决了。我们可以解决我提出的问题了,事实上只要搞清楚字面量是否进入常量池以及进入常量池的时间。那很多类似的问题都是一样的思路。这里有一个我觉得比较重要的点是,对内存有清楚的认识。比如new出来的实例大都是放在java heap里面的,而运行时常量池是在方法区里面的,这两块是完全隔离的。

以上。希望能有所帮助,如有理解偏差欢迎探讨。