StringBuffer&StringBuilder详解

序言

StringBuffer与StringBuilder是java.lang包下被大家熟知的两个类。其异同为:一、长度都是可扩充的;二、StringBuffer是线程安全的,StringBuilder是线程不安全的。那么他们的长度是如何实现动态扩充以及StringBuffer的线程安全是如何实现的呢?通过“深度”阅读它们的源代码,最终弄明白其中的缘由。

 

正文

首先上一张StringBuffer和StringBuilder类结构图:


 

抽象类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 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。 

 

  • AbstractStringBuilde

 

 

r这个抽象类提供了StringBuffer和StringBuilder绝大部分的实现。在

    •  

AbstractStringBuilder

    •  

的描述中说:如果去掉线程安全,那么

    •  

StringBuffer和StringBuilder是完全一致的。从实现的角度来说,StringBuffer所有方法(构造方法除外,因为没有必要)签名中都使用

    •  

synchronized

    •  

限定,也就是所有的方法都是同步的

    •  

eg.StringBuffer中replace()方法

 

1public synchronized StringBuffer replace(int start, int end, String str) {
2        super.replace(start, end, str);
3        return this;
4}

 

StringBuilder中replace():

 

1public StringBuilder replace(int start, int end, String str) {
2        super.replace(start, end, str);
3        return this;
4}

 

区别仅仅在方法签名上是否有synchronized。

另外需要稍稍注意的问题是:StringBuffer同步只同步目标,比如:sb.append("i am not synchronized"),sb是同步的,而其中的参数未必是同步的。

 

而它们两个可扩展长度则是通过ensureCapacity(int minimumCapacity)来验证当前长度是否小于参数minimumCapacity,如果成立则进行分配空间。分配新空间的步长为(当前长度+1)的两倍。

实现如下:

 

01public void ensureCapacity(int minimumCapacity) {
02        if (minimumCapacity > value.length) {
03            expandCapacity(minimumCapacity);
04        }
05}
06void expandCapacity(int minimumCapacity) {
07        int newCapacity = (value.length + 1) * 2;
08        if (newCapacity < 0) {
09            newCapacity = Integer.MAX_VALUE;
10        else if (minimumCapacity > newCapacity) {
11            newCapacity = minimumCapacity;
12        }
13        value = Arrays.copyOf(value, newCapacity);
14}

 

如果新的长度小于0(溢出了),则使用Integer的最大值作为长度。

 

另外,在阅读源码的过程中,发现两个有趣的问题,下面一一道来。

 

第一个,就是reverse的实现。其实我是第一次看StringBuilder和StringBuffer的源码,这里面的reverse的实现是我所知道的java中的最高效的实现,没有之一。

上源码,再做解释:

 

01public AbstractStringBuilder reverse() {
02        boolean hasSurrogate = false;
03        int n = count - 1;
04        for (int j = (n-1) >> 1; j >= 0; --j) {
05            char temp = value[j];
06            char temp2 = value[n - j];
07            if (!hasSurrogate) {
08                hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
09                    || (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
10            }
11            value[j] = temp2;
12            value[n - j] = temp;
13        }
14        if (hasSurrogate) {
15            // Reverse back all valid surrogate pairs
16            for (int i = 0; i < count - 1; i++) {
17                char c2 = value[i];
18                if (Character.isLowSurrogate(c2)) {
19                    char c1 = value[i + 1];
20                    if (Character.isHighSurrogate(c1)) {
21                        value[i++] = c1;
22                        value[i] = c2;
23                    }
24                }
25            }
26        }
27        return this;
28}

 

reverse分成两个部分:前面一个循环与后面的判断。

首先地一个循环很高效,循环次数为长度(count)的一半,而且使用>>位移运算,交换数组value[j]与value[n-j]的值。这里一是循环次数少,而是使用最高效的位移运算所以说这个reverse很高效。在反转过程中还完成了一件事:就是为hasSurrogate赋值。赋值的依据就是value[j]与value[n-j]两个字符时候有一个在\uD800和\uDFFF之间,如果有则赋值为true。

而hasSurrogate的值作为下面一个if分支的依据,如果为true,则从头到尾循环一遍。至于为何要判断hasSurrogate,以及下面一个循环的意义,请移步这里:http://www.oschina.net/question/129471_37064 

 

其实到这里应该已经结束了,在我整理StringBuffer和StringBuilder结构图时发现(“刨祖坟”行家啊),发现它们两个又再次实现了CharSequence接口,为何说再次呢,因为AbstractStringBuilder已经实现了一次,不知何为!经过几个人讨论,结果还要请您再次移步这里:http://www.oschina.net/question/129471_37096 

 

如果不对,有知道它们底细的,要通知我哦。

以上就是我在阅读StringBuffer和StringBuilder的收获,与大家分享。

本文同时发布于:http://congmo.github.com/2012/02/02/1.html

转载于:https://www.cnblogs.com/suifengbingzhu/archive/2012/09/07/2675586.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值