摘要:有关string,你一定看了不少的内容。你可能以前也看到过类似“new String(“xxx”)和String s2 = “Cat" 有什么区别?”之类的问题,那么你也许听说过String Pool这个概念。本文主要通过详解String Pool来尝试解答类似这样的问题。
正如她的名字一样,String Pool就是一个String的池,这个池是被存储在Java Heap Memory中的。公众号ImportSource之前的《原来JVM中的堆栈TM这么简单!》一文中提到过有关String Pool的内容(你可以关注importsource查看具体内容)。你可以移步了解。我们都知道String在java中是个特别special的类,我们除了可以通过双引号直接创建对象外(String s2 = "Cat"),还可以通过new String(“Cat”)这样的方式来创建对象。
下面我们就上一张图,这个图详细解释了在heap空间的字符串池(String Pool)是如何工作的。
相信你看了图以后大概明白了,之所以有String 池这种实现,是因为String在java中是不可变的(immutable)。并且这个池是一个“String interning理念”的实现。至于这个 String interning是个什么意思,这里你就可以理解为拷贝或者指向同一值,就像上图中的那样,s1和s2指向同一个 Cat,而不用再新开辟一格来再放入一个 Cat。另外这个String Pool的这种做法也是对设计模式中 Flyweight design pattern的一个运用。(有关设计模式的内容在我们公众号的底部点击“新人礼”可以查看源代码。)
String Pool帮Java Runtime节省了大量的空间,尽管她也使得我们创建一个String需要花更多的时间。没关系,凡事总有利弊。下面来说用new创建字符串和直接用双引号之间的区别。
当我们使用双引号的方式来创建一个字符串的时候,java runtime会首先去String池里找看有没有这个字符串,如果找到了,那么就返回这个串的引用,否则就会在池中新建一个String,然后再返回引用。
然而呢,如果我们使用new操作符来创建字符串对象的话,那么java就会强制String类创建一个新的字符串对象,正如你在上图中看到的一样,new出来的string并不在池中,但我们可以使用intern()方法把这个对象put到池中或者也可以把这个对象指向池中的另外一个具有相同值的对象上去。
下面是一个简单的例子。
StringPool.java
public class StringPool { /** * Java String Pool example * @param args */ public static void main(String[] args) { String s1 = "Cat"; String s2 = "Cat"; String s3 = new String("Cat"); System.out.println("s1 == s2 :"+(s1==s2)); System.out.println("s1 == s3 :"+(s1==s3)); } }
输出结果:
s1 == s2 :true s1 == s3 :false