java StringBuffer StringBulider 区别
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
String 类型和 StringBuffer 、StringBuilder 类型的主要性能区别其实在于 String 是不可变的对象,而后俩者都是可变的。
来看看 StringBuffer类源码定义:











抽象类AbstractStringBuilder(也是核心实现类)实现了Appendable和CharSequence两个接口;StringBuffer与StringBuilder统统继承自AbstractStringBuilder,并且实现了java.io.Serializable和CharSequence接口。
下面简单描述下这几个接口所起到的作用(引用自中文api)。
Appendable:能够被添加 char 序列和值的对象。如果某个类的实例打算接收java.util.Formatter 的格式化输出,那么该类必须实现 Appendable 接口。要添加的字符应该是有效的 Unicode 字符,正如 Unicode Character Representation 中描述的那样。注意,增补字符可能由多个 16 位char 值组成CharSequence:CharSequence 是 char 值的一个可读序列。此接口对许多不同种类的 char 序列提供统一的只读访问。char 值表示 Basic Multilingual Plane (BMP) 或代理项中的一个字符。有关详细信息,请参阅Unicode 字符表示形式。此接口不修改equals 和hashCode 方法的常规协定。因此,通常未定义比较实现 CharSequence 的两个对象的结果。每个对象都可以通过一个不同的类实现,而且不能保证每个类能够测试其实例与其他类的实例的相等性。因此,使用任意 CharSequence 实例作为集合中的元素或映射中的键是不合适的。Serializable:类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。AbstractStringBuilder这个抽象类提供了StringBuffer和StringBuilder绝大部分的实现。在AbstractStringBuilder的描述中说:如果去掉线程安全,那么StringBuffer和StringBuilder是完全一致的。从实现的角度来说,StringBuffer所有方法(构造方法除外,因为没有必要)签名中都使用synchronized限定,也就是所有的方法都是同步的。eg.StringBuffer中replace()方法
view sourceprint?1public synchronized StringBuffer replace(intstart, int end, String str) {2super.replace(start, end, str);3return this;4}StringBuilder中replace():
view sourceprint?1public StringBuilder replace(intstart, int end, String str) {2super.replace(start, end, str);3return this;4}区别仅仅在方法签名上是否有synchronized。
另外需要稍稍注意的问题是:StringBuffer同步只同步目标,比如:sb.append("i am not synchronized"),sb是同步的,而其中的参数未必是同步的。
而它们两个可扩展长度则是通过ensureCapacity(int minimumCapacity)来验证当前长度是否小于参数minimumCapacity,如果成立则进行分配空间。分配新空间的步长为(当前长度+1)的两倍。
实现如下:
view sourceprint?01public void ensureCapacity(intminimumCapacity) {02if (minimumCapacity > value.length) {03expandCapacity(minimumCapacity);04}05}06void expandCapacity(int minimumCapacity) {07int newCapacity = (value.length + 1) *2;08if (newCapacity < 0) {09newCapacity = Integer.MAX_VALUE;10} else if (minimumCapacity > newCapacity) {11newCapacity = minimumCapacity;12}13value = Arrays.copyOf(value, newCapacity);14}如果新的长度小于0(溢出了),则使用Integer的最大值作为长度。
另外,在阅读源码的过程中,发现两个有趣的问题,下面一一道来。
第一个,就是reverse的实现。其实我是第一次看StringBuilder和StringBuffer的源码,这里面的reverse的实现是我所知道的java中的最高效的实现,没有之一。
上源码,再做解释:
view sourceprint?01public AbstractStringBuilder reverse() {02boolean hasSurrogate = false;03int n = count - 1;04for (int j = (n-1) >>1; j >= 0; --j) {05char temp = value[j];06char temp2 = value[n - j];07if (!hasSurrogate) {08hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)09|| (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);10}11value[j] = temp2;12value[n - j] = temp;13}14if (hasSurrogate) {15// Reverse back all valid surrogate pairs16for (int i = 0; i < count -1; i++) {17char c2 = value[i];18if (Character.isLowSurrogate(c2)) {19char c1 = value[i + 1];20if (Character.isHighSurrogate(c1)) {21value[i++] = c1;22value[i] = c2;23}24}25}26}27return this;28}reverse分成两个部分:前面一个循环与后面的判断。
首先地一个循环很高效,循环次数为长度(count)的一半,而且使用>>位移运算,交换数组value[j]与value[n-j]的值。这里一是循环次数少,而是使用最高效的位移运算所以说这个reverse很高效。在反转过程中还完成了一件事:就是为hasSurrogate赋值。赋值的依据就是value[j]与value[n-j]两个字符时候有一个在\uD800和\uDFFF之间,如果有则赋值为true。