AbstractStringBuilder类源码阅读
AbstractStringBuilder类的作用
AbstractStringBuilder是一个抽象类,也是StringBuilder和StringBuffer类的父类,这个类是这两个类的共同点的体现。
AbstractStringBuilder类的类图
从类图中可以看出,
- 该类实现了Appendable接口,它的实现类的对象能够被添加 char 序列和值。如果某个类的实例打算接收取自 java.util.Formatter 的格式化输出,那么该类必须实现 Appendable 接口。
- 该类实现了CharSequence接口,CharSequence 是 char 值的一个可读序列。此接口对许多不同种类的 char 序列提供统一的只读访问
AbstractStringBuilder类的重点方法
属性变量
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
构造方法
/**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
}
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
构造方法也是非常简单,不过这里有个容易混淆的变量,capacity代表的容量,length代表的是长度,这两个变量是不同的。
精华方法
public void ensureCapacity(int minimumCapacity)
// 确保容量大小
public void ensureCapacity(int minimumCapacity) {
// 如果minimumCapacity 大于0,就开始内部确认容量
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
// 内部确认容量
private void ensureCapacityInternal(int minimumCapacity) {
// 如果minimumCapacity > value.length ,那么确定扩容
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
// 扩容方法
void expandCapacity(int minimumCapacity) {
// 将容量扩大到原来的2倍+2
int newCapacity = value.length * 2 + 2;
//如果扩大后没有达到需要的容量,将需要的容量设定为容量值
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
// 将数组扩大,完成扩容
value = Arrays.copyOf(value, newCapacity);
}
从源码中分析可以得知:他采取的扩容策略是:length*2+2,如果没有达到要求,会将需要的容量设置为容量值。
个人认为:这个方法是这个类中的精华,也是比较多人会提起的。
常用方法
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
将字符从此序列复制到目标字符数组 dst。要复制的第一个字符在索引 srcBegin 处;要复制的最后一个字符在索引 srcEnd-1 处。要复制的字符总数为 srcEnd-srcBegin。要复制到 dst 子数组的字符从索引 dstBegin 处开始,
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
if (srcBegin < 0)
throw new StringIndexOutOfBoundsException(srcBegin);
if ((srcEnd < 0) || (srcEnd > count))
throw new StringIndexOutOfBoundsException(srcEnd);
if (srcBegin > srcEnd)
throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
public AbstractStringBuilder append(String str)
按顺序追加 String 变量中的字符,使此序列增加该变量的长度。如果 str 为 null,则追加 4 个字符 “null”。
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
//如果需要扩容,会在这个方法中进行扩容
ensureCapacityInternal(count + len);
// 将str中的值在value后添加
str.getChars(0, len, value, count);
// 改变长度
count += len;
return this;
}
这个方法中需要注意的是扩容机制,因为如果不需要扩容的话,这个方法是很简单且高效的。
public AbstractStringBuilder delete(int start, int end)
移除此序列的子字符串中的字符。该子字符串从指定的 start 处开始,一直到索引 end - 1 处的字符,如果不存在这种字符,则一直到序列尾部。如果 start 等于 end,则不发生任何更改。
public AbstractStringBuilder delete(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
end = count;
if (start > end)
throw new StringIndexOutOfBoundsException();
int len = end - start;
if (len > 0) {
System.arraycopy(value, start+len, value, start, count-end);
count -= len;
}
return this;
}
public AbstractStringBuilder deleteCharAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
System.arraycopy(value, index+1, value, index, count-index-1);
count--;
return this;
}
对于需要移除的序列,并没有做一个清空的操作,只是将后面的值覆盖前面的值,并将长度缩减而已。
public AbstractStringBuilder replace(int start, int end, String str)
使用给定 String 中的字符替换此序列的子字符串中的字符。该子字符串从指定的 start 处开始,一直到索引 end - 1 处的字符,如果不存在这种字符,则一直到序列尾部。先将子字符串中的字符移除,然后将指定的 String 插入 start。(如果需要,序列将延长以适应指定的字符串。)
public AbstractStringBuilder replace(int start, int end, String str) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (start > count)
throw new StringIndexOutOfBoundsException("start > length()");
if (start > end)
throw new StringIndexOutOfBoundsException("start > end");
if (end > count)
end = count;
int len = str.length();
int newCount = count + len - (end - start);
//如果有需要,需要扩容
ensureCapacityInternal(newCount);
System.arraycopy(value, end, value, start + len, count - end);
str.getChars(value, start);
count = newCount;
return this;
}
这个方法的大概操作是这样的:先将value的值分为三段,第一段是删除区前面的称为d1,第二段是删除区称为d2,第三段是删除区之后的称为d3,
- 将d3的数据复制到 Vaule[start + len] 之后。(len的空间是为为替代的字符串空出来的)
- 将str的字符复制到value[start]之后
public String substring(int start, int end)
public String substring(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
throw new StringIndexOutOfBoundsException(end);
if (start > end)
throw new StringIndexOutOfBoundsException(end - start);
return new String(value, start, end - start);
}
很简单,直接new出一个新对象返回
说明
这个类中的方法很多,我们有一个一个的复制出来,只是将我觉得有代表性的方法复制出来和大家分享。
AbstractStringBuilder类涉及的设计模式
暂无发现
AbstractStringBuilder类的阅读感想
这是一个抽象类,但是我看完源码之后发现,就只有toString()方法是抽象的,其他都不是。也都基本实现了所有的功能。我觉得这个类设计出来可能就是作为一个代表。就是提供一个模板给我们去实现自己的可变的字符串的类。
这个类的主要让我们学习的是他的扩容方法,这个方法我觉得思考的地方有两个:什么时候扩容?一次扩容要多少合适?从源码中“minimumCapacity - value.length > 0”我们可以看出,只有当需要的容量大于数组的容量的时候才会扩容。并且一次扩容的数量是上一次的两倍加2。
阅读这个源码,我发现这个类的源码很多,刚刚开始的时候有点恐惧,感觉好像要花很多的时间来阅读和理解,其实不然,当我们深入了解之后,越是往下读,越是感觉了然于胸。我读了一遍之后,往回去看,有一种油然而生的自豪感。