简介
- StringBuffer是
Java1.0
的API,StringBuilder是Java1.5
的API - StringBuffer和StringBuilder都是
继承自AbstractStringBuilder
针对线程而言,
StringBuffer是线程安全的,
StringBuilder是线程不安全的
- 针对效率而言,StringBuffer效率较低,StringBuilder较为高效
String类特点
-
String类是被final修饰的
-
内部原理是一个char类型的字符数组
-
由于被final所修饰,所以它是采用定长数组存储数据的
-
由于是被final修饰的不可变类,因此不能被继承
private final char value[];
StringBuffer和StringBuilder的特点
- 都是被final修饰的类,不能被继承
- StringBuilder和StringBuffer都是动态字符序列,采用动态扩展算法(扩容、拷贝)来实现动态存储数据方式从而完成字符串的动态存储,因此它们是采用变长数组存储的
- 内部原理是一个char类型的字符数组
- StringBuilder和StringBuffer的内存对象是可变的,因此它们是一个可变字符序列
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence{ }
String,StringBuffer和StringBuilder之间的联系
- String 继承于CharSequence,因此String是CharSequence类型
- StringBuilder和StringBuffer同样实现了CharSequence 接口
- CharSequence是字符串,因此String,StringBuilder和StringBuffer本质上都是通过字符数组实现的
- CharSequence与String都能用于定义字符串,区别是CharSequence是
可读可写字符串
,而String是只读字符串
StringBuilder和StringBuffer的容量机制和扩容机制
StringBuilder和StringBuffer的容量机制和扩容机制相同,区别在于StringBuffer引入synchronized 关键字进行加锁操作,从而保证了线程安全,下文将展开详细叙述。
容量机制
初始容量的声明通过无参构造方法和有参构造方法两种方式进行声明
1、不声明长度,使用无参构造方法创建实例对象时,会调用父类的构造方法,
默认长度为16
public StringBuilder() {
super(16);//调用父类构造方法
}
2、使用有参构造方法有三种方式
public StringBuilder(int capacity) {
super(capacity);//调用父类构造方法
}
public StringBuilder(String str) {
super(str.length() + 16);//调用父类构造方法
append(str);
}
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
StringBuilder(int capacity)
构造一个不带字符具有指定初始长度
的字符串缓冲区
StringBuilder(String str)
构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。初始长度为当前字符长度+16
StringBuilder(CharSequence seq)
构造一个字符串缓冲区,它包含与指定的 CharSequence 相同的字符
综上,初始容量实际上就是创建了一个长度为16的字符数组。
StringBuilder继承了抽象类AbstractStringBuilder,其中有三个重要字段
char[] value;//保存字符
int count;//已有字符长度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//最大数组大小
value表示存储字符
,count表示数组中已有内容的长度,
MAX_ARRAY_SIZE
表示最大的分配容量,即,
若分配长度超过最大容量将会报OutOfMemoryError
的错误:请求的数组大小超过限制
StringBuilder的主要操作append,insert等都在value上进行,String则是每次操作new一个新String,因此StringBuilder和StringBuffer的效率要高于String
StringBuilder扩容方法如下所示
//如果传入的实际最小容量>0,调用容量检测方法并传入参数实际最小容量minimumCapacity
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
//如果传入的minimumCapacity比原来的value长度大,则调用newCapacity方法
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
//返回新数组,如果长度超过原数组长度,保留数组默认值
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
//扩大长度为原来的两倍加2
int newCapacity = (value.length << 1) + 2;
//如果新容量小于实际最小容量,将实际最小容量赋值给新容量
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
//如果新容量小于等于0或最大容量小于新容量,创建新容量
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
//如果最大容量小于实际最小容量,抛出异常
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
//如果实际最小容量大于最大容量返回实际最小容量,否则返回最大容量
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
StringBuffer的加锁操作
StringBuffer的各个方法都使用了synchronized关键字修饰进行加锁操作,下示为部分StringBuffer中的方法
@Override
public synchronized int length() {
return count;
}
@Override
public synchronized int capacity() {
return value.length;
}
@Override
public synchronized void ensureCapacity(int minimumCapacity) {
super.ensureCapacity(minimumCapacity);
}
synchronized关键字的作用是当一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞,从而增强了线程的安全性,不过与此同时也相应地降低了效率。