深入理解String与StringBuilder
对于这两者的区别,相信大多数学过java的朋友都能回答出来
String是不可变的字符串
StringBuilder是可变的字符串
然后呢?StringBuilder为什么是可变的,我们应该在什么时候使用StringBuilder,什么时候使用String呢?
首先我们需要了解一下为什么需要StringBuilder,其实我们使用String也可以实现字符串的修改呀,例如下面这样
String str="hello"; str=str+"world";
我们也可以完成字符串的修改。但这个+运算符内部到底是怎么操作的呢?我们用jdk自带的javap工具查看一下编译后的字节码
public static void main(java.lang.String[]); Code: 0: ldc #16 // String hello 2: astore_1 3: new #18 // class java/lang/StringBuilder 6: dup 7: aload_1 8: invokestatic #20 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 11: invokespecial #26 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 14: ldc #29 // String world 16: invokevirtual #31 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: invokevirtual #35 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: astore_1 23: return }
可以发现其内部底层也是使用的StringBuilder实现的,调用 + 运算符的时候实际调用的append方法,而不是在内存中开辟新的String内存存放字符串,再使str引用指向它。(其实一开始java的确是这么做的,不过这样会在内存中产生很多中间对象垃圾,造成性能下降)。
我们应该在何时使用StringBuilder呢?
既然java底层都帮我们做了这么好的优化了,我们是不是就可以肆无忌惮的使用String了呢,反正底层都已经用StringBuilder帮我们优化好了,的确在很多时候我们的确看不出区别,不过有时候就有区别了。比如下面 的栗子:
public static String testSb(String[] strs) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < strs.length; i++) { sb.append(strs[i]); } return sb.toString(); } public static String testS(String[] strs) { String str=""; for (int i = 0; i < strs.length; i++) { str+=strs[i]; } return str; }
在上面的代码中,testS()在循环中的时候,底层虽然也会通过StringBuilder进行优化,但是每次循环都会新建一个StringBuilder对象,所以会造成性能下降。
综上所述:在Thingking In Java这本书中就建议我们在编写对象的toString方法时,如果对象比较简单,我们就可以直接通过字符串相加返回值,如果操作中涉及到循环操作(例如容器类),最好就使用StringBuilder进行操作。