StringPool 与面试

1.问题起源

    public static void main(String[] args) {
    String s1 = "abc";
    String s2 = "ab";
    String s3 = "c";
    String s4 = s2 + s3;
    String st0 = "helloworld";
    String st1 = "helloworld";
    String st2 = "hello" + "world";
    System.out.println(st0 == st2);
    System.out.println(s1 == (s2 + s3));
    System.out.println(s1 == s4);

}

答案全是false,为什么呢?

2.String pool

就像名字说的一样,String pool就是String对象池,或者说是集合。在java堆中特地开辟出来的空间存储String对象。java引入String pool这一个结构来优化String对象的定位和存储。

String类型是Java最常用的类型,而且非常消耗内存。与其建立多份的String对象不如共享相同的实例对象。

3.举栗子

3.1

  public static void main(String[] args) {
    String s1 = "Cat";
    String s2 = "Cat";
   String  s3 = new String("Cat");     

    System.out.println(s1 == s2); //true
    System.out.println(s1 == "s3); //false
}</pre>

看图说话

众所周知,String对象是不可变的,值相同的String对象指向相同的实例。图中的Stringpool中值为“Cat”的String对象仅仅建立和存一次。当你再次使用String s2=“Cat”时 s2立刻指向了String pool中的“Cat”实例。这个只会在你使用硬编码,就是用字符串拼凑,一个一个字母输入的时候才会发生。s3使用了new建立了一个全新的String对象(“Cat”)它没有保存在String pool,而是保存在正常的堆中。

3.2

 

public static void main(String[] args) {
    String s1 = "Cat";
    String s2 = "Ca";
    s2 = s2 + "t";

    System.out.println(s1 == s2); //false

}</pre>

 String是不可变的,当使用“+”连接两个String对象时底层调用的是StringBuilder,利用StringBuilder进行字符串的拼接。这样会返回有个全新的String实例,并保存在堆中,并不会放入String Pool中。不想要创建新的String对象,想利用String pool中的实例,可以利用String.intern()方法,返回String pool里面的一个已有的String对象

 

String s1 = "abc";
String s2= "abc";

String s3 = new String("abc");

System.out.println(s1 == s2);
System.out.println(s1 == s3);

s3 = s3.intern();
System.out.println(s1==s3);


 

 

 

4.证明

public static void main(String[ ] arg){
    String s1 = "abc";
    String s2 = "ab";
    String s3 = "c";
    String s4 = s2 + s3;
    String st0 = "helloworld";
    String st1 = "helloworld";
    String st2 = "hello" + "world";
    System.out.println(st0 == st2);
    System.out.println(s1 == (s2 + s3));
    System.out.println(s1 == s4);
}</pre>

回到一开始的代码块,利用javap命令查看编译后的二进制class文件,截图如下:

从常量池中可以看出类型为String的常量只有#2("abc'),#3("ab"),#4("c"),#9("helloworld"),而且有StringBuilder类的相关方法的调用,验证了String "+"操作利用了StringBuilder.append()方法。