StringBuilder和StringBuffer源码分析
2016-05-30 15:21
567 查看
这篇文章主要针对Java中两个常用的操作字符串的类 StringBuilder和StringBuffer进行源码分析,感兴趣的小伙伴们可以参考一下
StringBuilder与StringBuffer是两个常用的操作字符串的类。大家都知道,StringBuilder是线程不安全的,而StringBuffer是线程安全的。前者是JDK1.5加入的,后者在JDK1.0就有了。下面分析一下它们的内部实现。
一、继承关系
?
可以看到,两个类的继承关系是一模一样的。Serializable是可以序列化的标志。CharSequence接口包含了charAt()、length() 、subSequence()、toString()这几个方法,String类也实现了这个接口。这里的重点是抽象类AbstractStringBuilder,这个类封装了StringBuilder和StringBuffer大部分操作的实现。
二、AbstractStringBuilder
1、变量及构造方法
?
AbstractStringBuilder内部用一个char[]数组保存字符串,可以在构造的时候指定初始容量方法。
2、扩容
?
publicvoid ensureCapacity(intminimumCapacity) {
if(minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
privatevoid ensureCapacityInternal(intminimumCapacity) {
// overflow-conscious code
if(minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
voidexpandCapacity(intminimumCapacity) {
intnewCapacity = value.length * 2+ 2;
if(newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if(newCapacity < 0) {
if(minimumCapacity < 0)// overflow
thrownew OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
扩容的方法最终是由expandCapacity()实现的,在这个方法中首先把容量扩大为原来的容量加2,如果此时仍小于指定的容量,那么就把新的容量设为minimumCapacity。然后判断是否溢出,如果溢出了,把容量设为Integer.MAX_VALUE。最后把value值进行拷贝,这显然是耗时操作。
3、append()方法
?
append()是最常用的方法,它有很多形式的重载。上面是其中一种,用于追加字符串。如果str是null,则会调用appendNull()方法。这个方法其实是追加了'n'、'u'、'l'、'l'这几个字符。如果不是null,则首先扩容,然后调用String的getChars()方法将str追加到value末尾。最后返回对象本身,所以append()可以连续调用。
三、StringBuilder
AbstractStringBuilder已经实现了大部分需要的方法,StringBuilder和StringBuffer只需要调用即可。下面来看看StringBuilder的实现。
1、构造器
?
可以看出,StringBuilder默认的容量大小为16。当然也可以指定初始容量,或者以一个已有的字符序列给StringBuilder对象赋初始值。
2、append()方法
?
append()的重载方法很多,这里随便列举了两个。显然,这里是直接调用的父类AbstractStringBuilder中的方法。
3、toString()
?
publicString toString() {
// Create a copy, don't share the array
returnnew String(value, 0, count);
}
toString()方法返回了一个新的String对象,与原来的对象不共享内存。其实AbstractStringBuilder中的subString()方法也是如此。
四、SringBuffer
StiringBuffer跟StringBuilder类似,只不过为了实现同步,很多方法使用lSynchronized修饰,如下面的方法:
?
可以看到,方法前面确实加了Synchronized。
另外,在上面的append()以及setLength()方法里面还有个变量toStringCache。这个变量是用于最近一次toString()方法的缓存,任何时候只要StringBuffer被修改了这个变量会被赋值为null。StringBuffer的toString如下:
?
publicsynchronized String toString() {
if(toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
returnnew String(toStringCache, true);
}
在这个方法中,如果toStringCache为null则先缓存。最终返回的String对象有点不同,这个构造方法还有个参数true。找到String的源码看一下:
?
原来这个构造方法构造出来的String对象并没有实际复制字符串,只是把value指向了构造参数,这是为了节省复制元素的时间。不过这个构造器是具有包访问权限,一般情况下是不能调用的。
总结
StringBuilder和StringBuffer都是可变字符串,前者线程不安全,后者线程安全。
StringBuilder和StringBuffer的大部分方法均调用父类AbstractStringBuilder的实现。其扩容机制首先是把容量变为原来容量的2倍加2。最大容量是Integer.MAX_VALUE,也就是0x7fffffff。
StringBuilder和StringBuffer的默认容量都是16,最好预先估计好字符串的大小避免扩容带来的时间消耗。
StringBuilder与StringBuffer是两个常用的操作字符串的类。大家都知道,StringBuilder是线程不安全的,而StringBuffer是线程安全的。前者是JDK1.5加入的,后者在JDK1.0就有了。下面分析一下它们的内部实现。
一、继承关系
?
publicfinal class StringBuffer extendsAbstractStringBuilder implementsjava.io.Serializable, CharSequence publicfinal class StringBuilder extendsAbstractStringBuilder implementsjava.io.Serializable, CharSequence
可以看到,两个类的继承关系是一模一样的。Serializable是可以序列化的标志。CharSequence接口包含了charAt()、length() 、subSequence()、toString()这几个方法,String类也实现了这个接口。这里的重点是抽象类AbstractStringBuilder,这个类封装了StringBuilder和StringBuffer大部分操作的实现。
二、AbstractStringBuilder
1、变量及构造方法
?
char[] value; intcount; AbstractStringBuilder() { } AbstractStringBuilder(intcapacity) { value = newchar[capacity]; }
AbstractStringBuilder内部用一个char[]数组保存字符串,可以在构造的时候指定初始容量方法。
2、扩容
?
publicvoid ensureCapacity(intminimumCapacity) {
if(minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
privatevoid ensureCapacityInternal(intminimumCapacity) {
// overflow-conscious code
if(minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
voidexpandCapacity(intminimumCapacity) {
intnewCapacity = value.length * 2+ 2;
if(newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if(newCapacity < 0) {
if(minimumCapacity < 0)// overflow
thrownew OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
扩容的方法最终是由expandCapacity()实现的,在这个方法中首先把容量扩大为原来的容量加2,如果此时仍小于指定的容量,那么就把新的容量设为minimumCapacity。然后判断是否溢出,如果溢出了,把容量设为Integer.MAX_VALUE。最后把value值进行拷贝,这显然是耗时操作。
3、append()方法
?
publicAbstractStringBuilder append(String str) { if(str == null) returnappendNull(); intlen = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; returnthis; }
append()是最常用的方法,它有很多形式的重载。上面是其中一种,用于追加字符串。如果str是null,则会调用appendNull()方法。这个方法其实是追加了'n'、'u'、'l'、'l'这几个字符。如果不是null,则首先扩容,然后调用String的getChars()方法将str追加到value末尾。最后返回对象本身,所以append()可以连续调用。
三、StringBuilder
AbstractStringBuilder已经实现了大部分需要的方法,StringBuilder和StringBuffer只需要调用即可。下面来看看StringBuilder的实现。
1、构造器
?
publicStringBuilder() { super(16); } publicStringBuilder(intcapacity) { super(capacity); } publicStringBuilder(String str) { super(str.length() + 16); append(str); } publicStringBuilder(CharSequence seq) { this(seq.length() + 16); append(seq); }
可以看出,StringBuilder默认的容量大小为16。当然也可以指定初始容量,或者以一个已有的字符序列给StringBuilder对象赋初始值。
2、append()方法
?
publicStringBuilder append(String str) { super.append(str); returnthis; } publicStringBuilder append(CharSequence s) { super.append(s); returnthis; }
append()的重载方法很多,这里随便列举了两个。显然,这里是直接调用的父类AbstractStringBuilder中的方法。
3、toString()
?
publicString toString() {
// Create a copy, don't share the array
returnnew String(value, 0, count);
}
toString()方法返回了一个新的String对象,与原来的对象不共享内存。其实AbstractStringBuilder中的subString()方法也是如此。
四、SringBuffer
StiringBuffer跟StringBuilder类似,只不过为了实现同步,很多方法使用lSynchronized修饰,如下面的方法:
?
publicsynchronized int length() { returncount; } publicsynchronized StringBuffer append(String str) { toStringCache = null; super.append(str); returnthis; } publicsynchronized void setLength(intnewLength) { toStringCache = null; super.setLength(newLength); }
可以看到,方法前面确实加了Synchronized。
另外,在上面的append()以及setLength()方法里面还有个变量toStringCache。这个变量是用于最近一次toString()方法的缓存,任何时候只要StringBuffer被修改了这个变量会被赋值为null。StringBuffer的toString如下:
?
publicsynchronized String toString() {
if(toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
returnnew String(toStringCache, true);
}
在这个方法中,如果toStringCache为null则先缓存。最终返回的String对象有点不同,这个构造方法还有个参数true。找到String的源码看一下:
?
String(char[] value, booleanshare) { // assert share : "unshared not supported"; this.value = value; }
原来这个构造方法构造出来的String对象并没有实际复制字符串,只是把value指向了构造参数,这是为了节省复制元素的时间。不过这个构造器是具有包访问权限,一般情况下是不能调用的。
总结
StringBuilder和StringBuffer都是可变字符串,前者线程不安全,后者线程安全。
StringBuilder和StringBuffer的大部分方法均调用父类AbstractStringBuilder的实现。其扩容机制首先是把容量变为原来容量的2倍加2。最大容量是Integer.MAX_VALUE,也就是0x7fffffff。
StringBuilder和StringBuffer的默认容量都是16,最好预先估计好字符串的大小避免扩容带来的时间消耗。
相关文章推荐
- Android Studio 2.2 预览版 - 全新的 UI 设计器和约束布局
- iOS开发 - 第02篇 - UI进阶 - 08 - 私人通讯录
- SQLSERVER TRUE、FALSE、UNKNOWN
- The constructor BASE64Encoder() is not accessible due to restriction on required
- iOS开发之:dispatch_async 与 dispatch_get_global_queue 的使用方法
- ArrayBlockingQueue源码中为什么方法要用局部变量引用类变量
- IBM MQQueueManager 直接连接
- Java中String、StringBuffer、StringBuilder的区别及面试经常出现的问题
- 存储过程 返回值 procedure return values
- Java中String、StringBuffer、StringBuilder的区别及面试经常出现的问题
- PKIX path building failed 的问题
- ueditor 跨域上传问题
- DECLARE_WAITQUEUE(wait, current)的分析
- UI进阶 SQLite错误码
- UIDatePicker 轮转日期选择器 时间选择器
- 解决UIScrollView和滑动返回手势的冲突
- Android高级UI GestureDetector监听各种手势
- ValidateRequest="false"
- iOS的QuickTime Plugin
- UITableViewCell上的按钮点击事件处理