StringBuilder和StringBuffer:
这两个类的实现原理基本相同,但StringBuffer是线程安全的,StringBuilder是非线程安全的。所以如果分析这两个类避不开
AbstractStringBuilder抽象类。
在多线程中推荐使用StringBuffer,如果在单线程情况中使用StringBuilder会更好,StringBuilder没有锁,执行速度会更快。StringBuffer和StringBuilder都比String执行速度块。
学习内容:
StringBuffer和StringBuilder他们两都继承了AbstractStringBuilder抽象类,他们的底层都是可变的字符数组,所以在进行频繁的字符串操作时,建议使用StringBuffer和 StringBuilder来进行操作。 另外StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
String是不可变的字符串缓存区,而StringBuffer和StringBuffer是可变的字符串缓存区。
源码分析:
1.继承和接口图
StringBuilder和StringBuffer都继承了AbstractStringBuilder抽象类,在String源码分析中,String和StringBuffer或者StringBuilder比较是否相等的方法。
nonSyncContentEquals(AbstractStringBuilder sb)
2.构造方法
StringBuilder:
// StringBuilder的构造方法都是调用了父类的构造方法
public StringBuilder() {
super(16);
}
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);
}
StringBuffer:
// StringBuffer的构造方法都是调用了父类的构造方法
public StringBuffer() {
super(16);
}
public StringBuffer(int capacity) {
super(capacity);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
AbstractStringBuilder类:
// 无参构造并没有被调用
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
结论:StringBuffer和StringBuilder创建时都是通过其父类 AbstractStringBuilder。
1.无参数时,每次默认都是创建长度为16的字符串缓存区。
2.传入int capacity参数时,创建长度为capacity的字符串缓存区
3.但当传入字符串或字符数组时,字符串缓存区长度 = 传入字符串长度+16
3.成员变量
StringBuilder:
// 序列化id(版本号) 序列化时不会进行序列化,而是复制一个进行序列化
static final long serialVersionUID = 4383685877147921099L;
StringBuffer:
// 序列化id(版本号) 序列化时不会进行序列化,而是复制一个进行序列化 static
静态变量不能被序列化,会出现错值。
static final long serialVersionUID = 3388685877147921107L;
//toStringCache用transient修饰,表示该字段不可序列化。他用于缓存toString最后一次返回的值,当修改的时候缓存会被清除。数组一旦修改,将会改变。
private transient char[] toStringCache;
//用于序列化的,序列化value,count,shared
private static final java.io.ObjectStreamField[] serialPersistentFields =
{
new java.io.ObjectStreamField("value", char[].class),
new java.io.ObjectStreamField("count", Integer.TYPE),
new java.io.ObjectStreamField("shared", Boolean.TYPE),
};
AbstractStringBuilder:
// 字符数组 可变的没有用final修饰
char[] value;
// 字符数组中被占用的个数 即字符串长度
int count;
// 最大长度为Integer最大值减8 即数组最大长度为Integer最大值减8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
结论:
1.StringBuffer比StringBuilder多了两个成员变量
toStringCache:用来提升StringBuffer的toString()输出,在数组未改变,将缓存最后一次toString的数组结果,如果数组发生了改变,将清除缓存。
serialPersistentFields:用于序列化的,序列化value,count,shared
2.AbstractStringBuilder、StringBuffer、StringBuilder的数组最大上限是Integer.MAX_VALUE-8
3.与String不同的是,StringBuilder和StringBuffer的数组都是可变的,而String是copy产生一个新的数组,内存地址不同了。
4.方法
对于方法的比较,我将对分析的方法列举三个一同看。
// 对于append方法,StringBuffer和StringBuilder使用父类的append,
// 但是StringBuffer会在append的之前将toStringCache清空
// StringBuffer
public synchronized StringBuffer append(Object obj) {
toStringCache = null;
super.append(String.valueOf(obj));
return this;
}
// StringBuilder
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
直接看AbstractStringBuilder
// 传字符串
public AbstractStringBuilder append(String str) {
if (str == null) // 如果是null 就返回null
return appendNull();
int len = str.length(); // 字符串长度
// 验证一下数组长度是否够用 (已占用的长度+字符串长度 > 数组总长度)大于执行扩容
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count); // 调用String的getChars 将字符串复制到value后面
count += len; // count = count + len
return this;
}
// 传的是对象,调用String类中valueOf(obj) 然后调用传字符串的append方法
// String类 return (obj == null) ? "null" : obj.toString();
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
// 传StringBuilder
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null) // 判断是否为null
return appendNull();
int len = sb.length(); // 字符串长度
// 验证一下数组长度是否够用 (已占用的长度+字符串长度 > 数组总长度)大于执行扩容
ensureCapacityInternal(count + len);
// 调用String的getChars 将字符串复制到value后面
sb.getChars(0, len, value, count);
count += len; // count = count + len
return this;
}
// 传StringBuffer 和上面一样
AbstractStringBuilder append(AbstractStringBuilder asb) {
if (asb == null)
return appendNull();
int len = asb.length();
ensureCapacityInternal(count + len);
asb.getChars(0, len, value, count);
count += len;
return this;
}
// 传的是CharSequence接口 char StringBuffer StringBuilder String 和上面一样
public AbstractStringBuilder append(CharSequence s) {
if (s == null)
return appendNull();
if (s instanceof String)
return this.append((String)s);
if (s instanceof AbstractStringBuilder)
return this.append((AbstractStringBuilder)s);
return this.append(s, 0, s.length());
}
多个append方法都判断了传进来的对象是否为null,然后调用 appendNull()方法
// 直接存储一个null
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4); // 判断 已占用+4 是否超过数组长度,超过开始扩容
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
在append()方法中都调用了 ensureCapacityInternal(int minimumCapacity) 方法
// 判断是否空间是否够用 不够扩容 够了就算了
// minimumCapacity: 已占用的长度 + 需要加的长度
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) { // 不够用调取扩容方法看下面
value = Arrays.copyOf(value, // 只是将对象里的char重新构造了一个数组长度更大的数组
newCapacity(minimumCapacity));
}
}
// 扩容算法 计算需要扩容为多大的长度 minCapacity 已占用长度 + 需要加的长度
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2; // 扩容长度算法 总长度 * 2 + 2
if (newCapacity - minCapacity < 0) { // 判断够用不
newCapacity = minCapacity; // 不够用 就扩容到传进来的长度 已占用长度 + 需要加的长度
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) // 判断是否超出最大值范围 最大为Integer.MAX_VALUE-8
? hugeCapacity(minCapacity) // 超了抛出异常 没超出就返回minCapacity 相等就是MAX_ARRAY_SIZE即Integer.MAX_VALUE-8
: newCapacity;
}
这里其他相关的方法基本与String中的一致,不再分析了。