看题目就知道本文要说啥了~先上代码!!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滴???