关于String与StringBuilder的提问与总结

看题目就知道本文要说啥了~先上代码!!java

public class StringAndStringBuilderTest {
    
    @Test
    public void testString() {
        String str = "";
        for(int i = 0; i < 100; i++) {
            str += String.valueOf(i);
        }
    }

    @Test
    public void testStringBuilder() {
        StringBuilder sb = new StringBuilder("");
        for(int i = 0; i < 100; i++) {
            sb.append(String.valueOf(i));
        }
    }

    @Test
    public void testString() {
        String str = "a" + "b" + "c";
    }
}

上述代码很明显,分别测试:String链接产生多少对象?SringBuilder链接产生多少对象?在一条表达式中链接字符串产生多少对象?缓存

下面在给出该类的字节码文件。。。app

public class StringAndStringBuilder {
  public StringAndStringBuilder();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public void testString();
    Code:
       0: ldc           #2                  // String 
       2: astore_1      
       3: iconst_0      
       4: istore_2      
       5: iload_2       
       6: bipush        100
       8: if_icmpge     39
      11: new           #3                  // class java/lang/StringBuilder
      14: dup           
      15: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      18: aload_1       
      19: invokevirtual #5                  // Method java/lang/StringBuilder.append:
                                                (Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: iload_2       
      23: invokestatic  #6                  // Method java/lang/String.valueOf:
                                                (I)Ljava/lang/String;
                                            //产生一个String对象,并追加到StringBuilder后面
      26: invokevirtual #5                  // Method java/lang/StringBuilder.append:
                                                (Ljava/lang/String;)Ljava/lang/StringBuilder;
      29: invokevirtual #7                  // Method java/lang/StringBuilder.toString:
                                                ()Ljava/lang/String;
      32: astore_1      
      33: iinc          2, 1
      36: goto          5                    //作了个for循环,返回第5行
      39: return        

  public void testStringBuilder();
    Code:
       0: new           #3                  // class java/lang/StringBuilder
       3: dup           
       4: ldc           #2                  // String 
       6: invokespecial #8                  // Method java/lang/StringBuilder."<init>":
                                                (Ljava/lang/String;)V
       9: astore_1      
      10: bipush        100
      12: istore_2      
      13: iload_2       
      14: sipush        200
      17: if_icmpge     35
      20: aload_1       
      21: iload_2       
      22: invokestatic  #6                  // Method java/lang/String.valueOf:
                                                (I)Ljava/lang/String;
                                            //append方法里,再次产生一个String对象
      25: invokevirtual #5                  // Method java/lang/StringBuilder.append:
                                                (Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: pop           
      29: iinc          2, 1
      32: goto          13                    //同理,此处为循环,返回第13行
      35: return        

  public void testString02();
    Code:
       0: ldc           #9                  // String abc
                                            //这是个问题~~
       2: astore_1      
       3: return        
}

先看testString方法的字节码:jvm

从iload_2开始,到goto,是个完整的循环体。请看第一份Java代码测试

字节码的第11--32行,编译器自动将String链接转化为StringBuilder,并推入其缓存池。并将原String引用指向该StringBuilder的toString方法返回的String对象。ui

在第29行可见,最后调用toString并返回对象;第32行可见,依然从栈中弹出原来Srting引用str。code

因此,直接用String链接字符串的话,每用一次String的原引用,则会生成一个StringBuilder对象。对象

综上所述,当缓存池非空时或原String非null,至少产生两个对象,一个String,一个StringBuilder。当追加在StringBuilder后面的String并不存在与常量池,则最多产生2N+1个对象.ip


在看testStringBuilder方法的字节码:ci

第13--32行,依然是个完整的循环体,请看第一份Java代码

见字节码,明显与testString方法大不同。清晰不少。

循环体内,并没有StringBuilder对象的产生,只有String.valueOf()方法生成出来的,要追加到StringBuilder的String对象。

显然每次循环,少了StringBuilder对象的生成。

综上所述,当缓存池非空时,至少产生两个对象;当不断得往缓存池里追加字符串时,且新字符串并不存在于常量池,则最多产生N+1个对象。

testSting()产生2N+1个对象,testStringBuilder()产生N+1个对象,这就是StringBuilder链接字符串比String高效的缘故。

StringBuffer同理。


再看最后一个方法testString02()。。。

String str = "a" + "b" + "c" ;

真的只产生一个对象么?字节码只是表示出,从字符串常量池中弹出引用,并没有说明JVM解析CONSTANT_String时,产生多少个String对象。

因此,求大侠解答最后提出的问题。jvm是如何解析CONSTANT_String滴???

相关文章
相关标签/搜索