String 、StringBuffer 与StringBuilder的异同详解
在声明方面:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence
String、StringBuffer、StringBuilder都实现了CharSequence接口和Serializable接口 ;
String、StringBuffer、StringBuilder都是final不可继承和重写;
String实现了字符串比较的Comparable接口;
StringBuffer和StringBuilder都继承AbstractStringBuilder抽象类;
在字符串拼接效率上:
String<StringBuffer<StringBuilder,但是如果是String str=“a”+“b”+“c“是效率最高的。因为”a“、”b“、”c“都在字符串常量池里面。就是直接在常量池将a、b、c拼接成abc再放入字符串常量池。
如果没有这三句赋值String s1=”a”;String s2=”b”;String s3=”c”;
String str=“a”+“b”+“c“;这句语句会生成4个新对象均放入字符串常量池中
如图:
测试如图
public static void main(String[] args) { StringBuilder strB = new StringBuilder(); // String str = new String(); String a1 = "1"; String b1 = "2"; String c1 = "3"; String d1 = "3"; String e1 = "3"; String f1 = "3"; String g1 = "3"; String h1 = "3"; String i1 = "3"; long startTime = System.nanoTime(); // strB.append(a1).append(b1).append(c1).append(d1).append(e1).append(f1).append(g1).append(h1).append(i1); // strB.append(a1);strB.append(b1);strB.append(c1);strB.append(d1); // strB.append(e1);strB.append(f1);strB.append(g1);strB.append(h1);strB.append(i1); strB.append("a").append("b").append("c").append("d").append("e").append("f").append("g").append("h").append("i"); long endTime = System.nanoTime(); System.out.println(endTime-startTime); long startTime1 = System.nanoTime(); // str +=a1;str +=b1;str +=c1;str +=d1;str +=e1;str +=f1;str +=g1;str +=h1;str +=i1; // str = a1 + b1 + c1 + d1 + e1 + f1 + g1 + h1 + i1; String str = "j"+"k"+"l"+"m"+"n"+"o"+"p"+"q"+"r"; long endTime1 = System.nanoTime(); System.out.println(endTime1-startTime1); }第一行是StringBuilder,第二行String。
显然String的操作快很多。
而如果是类似下图的String拼接(其实质是通过StringBuilder的append方法来拼接,但是每次都会返回一个String对象,存放在堆中)。可以通过IDE的debug的Force step into调试看出来。
public static void main(String[] args) { StringBuilder strB = new StringBuilder(); String str = new String(); String a1 = "1"; String b1 = "2"; String c1 = "3"; String d1 = "3"; String e1 = "3"; String f1 = "3"; String g1 = "3"; String h1 = "3"; String i1 = "3"; long startTime = System.nanoTime(); // strB.append(a1).append(b1).append(c1).append(d1).append(e1).append(f1).append(g1).append(h1).append(i1); strB.append(a1);strB.append(b1);strB.append(c1);strB.append(d1); strB.append(e1);strB.append(f1);strB.append(g1);strB.append(h1);strB.append(i1); long endTime = System.nanoTime(); System.out.println(endTime-startTime); long startTime1 = System.nanoTime(); str +=a1;str +=b1;str +=c1;str +=d1;str +=e1;str +=f1;str +=g1;str +=h1;str +=i1; long endTime1 = System.nanoTime(); System.out.println(endTime1-startTime1); }
第一行是StringBuilder,第二行String。
其主要是在字符串拼接过程中StringBuilder不会生成新的StringBuilder对象,而String每次都会生成新String对象放入堆内存中,虽然他们的拼接都是用StringBuilder的方法。
也因此,如果是如下图的String的字符串拼接,就会发现如果两者字符串拼接效率是相近的。
public static void main(String[] args) { StringBuilder strB = new StringBuilder(); String str = new String(); String a1 = "1"; String b1 = "2"; String c1 = "3"; String d1 = "3"; String e1 = "3"; String f1 = "3"; String g1 = "3"; String h1 = "3"; String i1 = "3"; long startTime = System.nanoTime(); // strB.append(a1).append(b1).append(c1).append(d1).append(e1).append(f1).append(g1).append(h1).append(i1); strB.append(a1);strB.append(b1);strB.append(c1);strB.append(d1); strB.append(e1);strB.append(f1);strB.append(g1);strB.append(h1);strB.append(i1); long endTime = System.nanoTime(); System.out.println(endTime-startTime); long startTime1 = System.nanoTime(); // str +=a1;str +=b1;str +=c1;str +=d1;str +=e1;str +=f1;str +=g1;str +=h1;str +=i1; str = a1 + b1 + c1 + d1 + e1 + f1 + g1 + h1 + i1; long endTime1 = System.nanoTime(); System.out.println(endTime1-startTime1); }
第一行是StringBuilder,第二行String。
StringBuilder的构造默认容量为16
public StringBuilder() { super(16); }
如下图是StringBuilder的父类AbstractStringBuilder里面的的扩容方法,
把 (长度)×2+2;
private int newCapacity(int minCapacity) { // overflow-conscious code int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; }
StringBuffer与StringBuilder差不多,因为StringBuffer也是继承抽象类
AbstractStringBuilder,所以StringBuffer在与String类型字符串拼接效率上比较也是比String类型的要快。其次就是跟StringBuilder比较主要是StringBuffer的大多数方法加了syncronized关键字,也因此StringBuffer是线程安全的,StringBuilder是非线程安全的。
public static void main(String[] args) { String a1 = "1"; String b1 = "2"; String c1 = "2"; String d1 = "3"; String e1 = "3"; String f1 = "3"; String g1 = "3"; String h1 = "3"; String i1 = "3"; StringBuilder sbd = new StringBuilder(); StringBuffer sb = new StringBuffer(); long startTime = System.nanoTime(); sbd.append(a1);sbd.append(b1);sbd.append(c1);sbd.append(d1); sbd.append(e1);sbd.append(f1);sbd.append(g1);sbd.append(h1);sbd.append(i1); long endTime = System.nanoTime(); System.out.println(endTime - startTime); long startTime1 = System.nanoTime(); sb.append(a1);sb.append(b1);sb.append(c1);sb.append(d1); sb.append(e1);sb.append(f1);sb.append(g1);sb.append(h1);sb.append(i1); long endTime1 = System.nanoTime(); System.out.println(endTime1 - startTime1); }
第一行是StringBuilder的,第二行是Stringbuffer的
发现其实差不多,因此线程安全的情况下用StringBuilder,非线程安全用StringBuffer。主要还是具体情况具体分析。