String ,StringBuilder,StringBuffer的区别
String类代表字符串,java程序中所有的字符串字面值(如”abc”)都作为此类来实现,字符串是常量,它们的值在创建后就不能改变。因为字符串不可变,因此可以共享它们。
StringBuffer,线程安全的可变字符序列。一个类似于String的字符缓冲区,但不能修改,是指这个对象本身不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
StringBuilder, 一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。
有时候,我们经常会这样写程序,譬如
?然后我们运行程序,控制台便马上打印出了我们想要的结果。可是,在这个程序片段的内部,它的执行机理以及这样写,性能上是个什么样的情况,我们可能很少去研究,下面我将来谈一谈重载的’+’操作符与StringBuilder的区别。
首先,我们先说String。众所周知,String是java.lang包中的一个类,它在java编程中使用的非常频繁。查看javaAPI可以看到,这个类的声明是public final class String….,正因为是final的,可以想到这个类已经创建,那么它就是不可变的。有了这个认识,我们再说上面的程序,每用’+’操作符对String对象进行一次运算,那么它都会产生一个新的String对象,这个新产生的String对象既包含原来的String对象也包含添加进来的String对象。毫无疑问,上面那段代码必定能很好的工作,只是为了把几个字符串拼接到一起,按照上面的做法会产生大量的”中间”String对象,这些中间对象也是需要被GC回收的。为了看清楚这段代码的执行细节,我们可以用这么一个命令?
Javap? c? Concatenation
控制台给我们列出了这样的信息:public java.lang.String implicit(java.lang.String[]); Code: 0: ldc #16; //String 2: astore_2 3: iconst_0 4: istore_3 5: goto 32 8: new #18; //class java/lang/StringBuilder 11: dup 12: aload_2 13: invokestatic #20; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 16: invokespecial #26; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 19: aload_1 20: iload_3 21: aaload 22: invokevirtual #29; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 25: invokevirtual #33; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 28: astore_2 29: iinc 3, 1 32: iload_333: aload_1 34: arraylength35: if_icmplt 8 38: aload_2 39: areturnpublic java.lang.String explicit(java.lang.String[]); Code: 0: new #18; //class java/lang/StringBuilder 3: dup 4: invokespecial #45; //Method java/lang/StringBuilder."<init>":()V 7: astore_2 8: iconst_0 9: istore_3 10: goto 24 13: aload_2 14: aload_1 15: iload_3 16: aaload 17: invokevirtual #29; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 20: pop 21: iinc 3, 1 24: iload_3 25: aload_1 26: arraylength 27: if_icmplt 13 30: aload_2 31: invokevirtual #33; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 34: areturn?
从两分字节码可以看出,第二个的更短小简洁,并且第一个在每个循环中都会创建一个StringBuilder对象,而第二个方法始终只有一个StringBuilder对象。然而这两者的性能差异确实有很大差别的。
所以,当我们的连接操作很简单的时候,可以使用String,但是若涉及到循环,那么最好使用StrignBuilder.?