String 在java中是不可变的,每个对String进行操作的方法实际上都是返回一个新的String对象,并使原来的String对象不可达。对String的连接常有下面几种方法,一种是使用‘+’符
String 在java中是不可变的,每个对String进行操作的方法实际上都是返回一个新的String对象,并使原来的String对象不可达。对String的连接常有下面几种方法,一种是使用‘+’符号,另一种是使用StringBuilder,再就是String的concat方法。
(1) ‘+’:
为了研究'+'的实现,我们写以下测试代码:
public static void main(String[] args) { String a="hell"+"o"; //code1 String b="world"; for(int i=0;i<4;i++) { a+=b; //code2 }}
把上面代码编译后再用jdk的反编译工具(javap)反编译下,得到如下代码: public static void main(java.lang.String[]); Code: 0: ldc #16; //String hello 2: astore_1 3: ldc #18; //String world 5: astore_2 6: iconst_0 7: istore_3 8: goto 33 11: new #20; //class java/lang/StringBuilder 14: dup 15: aload_1 16: invokestatic #22; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 19: invokespecial #28; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 22: aload_2 23: invokevirtual #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 26: invokevirtual #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 29: astore_1 30: iinc 3, 1 33: iload_3 34: iconst_4 35: if_icmplt 11 38: return
从code1可以得到“如果在‘+’左右没有变量的时候,‘+‘的结果是直接得出的。 从code2可以得到,如果在‘+’左右有变量的时候,会生成一个StringBuilder对象,然后调用其append方法。
在一个拼接String的语句中,如果被拼接的String中有String对象,那这个语句会生成一个StringBuilder对象,然后调用其append方法.
注意源码中的循环,反编译后在代码中对应的是<line>8</line>到<line>35</line>,而创建StringBuilder对象被包含在了循环内,所以上面的代码会创建过多StringBuilder对象而影响效率。
(2) StringBuilder
下面我们来分析下StringBuilder的append方法,其源码如下:
public StringBuilder append(String str) { super.append(str); return this; }
super.append(str)如下: public AbstractStringBuilder append(String str) { if (str == null) str = "null"; int len = str.length(); if (len == 0) return this; int newCount = count + len; if (newCount > value.length) expandCapacity(newCount);//此方法拓展StringBuilder的容量至当前容量的2倍 str.getChars(0, len, value, count); count = newCount; return this; }
通过分析源码我们可以发现StringBuilder的效率是很高的(这也是java编译器默认采用StringBuilder的原因),但要注意拓展容量的操作,所以适当设置初始容量是很有必要的。 (3)String的concat方法
其源码如下:
public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } char buf[] = new char[count + otherLen]; getChars(0, count, buf, 0); str.getChars(0, otherLen, buf, count); return new String(0, count + otherLen, buf); }
这个方法的作用很简单,就是创建一个新String对象。
结论:
定义三个变量:String a="a",b="b",c="c";
1.对于简单拼接,如String d=a+b,建议使用concat方法:String d=a.concat(b);来减少生成不必要的StringBuilder对象
2.对于二次以上拼接,如String d=a+b+c,使用这种方式就可以
3.对于涉及到循环的拼接,如:
String d="";String e="";for(int i=0;i<10;i++) { d+=a;//或d=d+a; e+=(a+b);//或e=e+a+b;}
建议采用以下方式:
StringBuilder d = new StringBuilder(10)//设置初始容量以减少拓容操作StringBuilder e = new StringBuilder(20);for(int i=0;i<10;i++) { d.append(a); e.append(a).append(b);}
#本文参考自《thinking in java》第四版Strings章节