按我的习惯,使用StringBuffer比使用StringBuilder多得多,因为在我的记忆中,曾经看过一篇文章,忘记是谁写的了,那篇文章告诉我StringBuffer是非线程安全的,而StringBuilder是线程安全的,直到今天我又查询了一下两者的区别,发现StringBuffer才是线程安全的。这让我迷惑了,还是亲自去查询一下源码吧:
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence { /** 省略部分代码 */ @Override public synchronized int length() { return count; } @Override public synchronized int capacity() { return value.length; } @Override public synchronized void ensureCapacity(int minimumCapacity) { if (minimumCapacity > value.length) { expandCapacity(minimumCapacity); } } @Override public synchronized void setCharAt(int index, char ch) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); toStringCache = null; value[index] = ch; } @Override public synchronized StringBuffer append(Object obj) { toStringCache = null; super.append(String.valueOf(obj)); return this; } @Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } /** 省略部分代码 */ }
从源码看出,StringBuffer很多方法都使用了synchronized进行同步,所以它是线程安全的,而StringBuilder是非线程安全的。所以在单线程中,StringBuilder的效率要高于StringBuffer。看来以后我得改改习惯,优先考虑使用StringBuilder了。
再说说String类,String是一个特殊的引用类,它是一个不可变的字符串:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** 省略部分代码 */ public native String intern(); }
之所以说它不可变,是因为其内部使用final char[]类型来存储字符串,final字段经过初始化后不能再次改变。
值得一提的是,String提供了一个方法intern(),它的作用在于:返回字符串对象的规范化表示形式。当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。
String a = "a";
String aa = new String(a);
System.out.println(a == aa); //false
System.out.println(a == aa.intern()); //true
与String相较而言,StringBuffer和StringBuilder则是可变字符串。