前言
月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂)
央是一片海洋,海乃百川,代表着一块海绵(吸纳万物)
泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出)
月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容
希望大家一起坚持这个过程,也同样希望大家最终都能从零到零,把知识从薄变厚,再由厚变薄!
1.AbstractStringBuilder的作用:
- 首先该抽象类是对StringBuilder和StringBuffer的具体抽象,这两个子类的大部分方法都是覆盖该抽象类的方法
- 源码注释中提到,该抽象类是一串可变的字符串(A mutable sequence of characters),意味着该实体类即是对字符串进行特点的操作
- 当把null参数传给某些方法和构造器时,会抛出空指针异常,这点是我们需要特别注意的
2.AbstractStringBuilder的类图
AbstractStringBuilder是有实现两个接口:
a).一个CharSequence,这个接口是一串可读的序列化的字节值,主要是为了规范对于char字节操作的一些规范,详情请点击下面链接
......(假装这个是链接,以后补充)
b).一个Appendable,这个接口是为了方便那些可直接进行附加字符序列和值的对象,比如StringBuffer的append()方法,可以一直接在方法后面添加字符.详情请点击下面链接
JDK1.8源码学习--lang包(Appendable)_w5_Silence的博客-CSDN博客
3.成员变量
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
/**
* The maximum size of array to allocate (unless necessary).
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
一个成员变量是字节数组用来记录字节的值,因为大家都知道字符串在底层存的时候都是存的字节数组.
另一个成员变量是记录了该数组使用的长度.因为当前数组的容量并不一定和已使用的容量相同,所以保持一个成员变量来记录已经使用的容量
最后一个私有的成员变量源码中提及到有一些虚拟接会保留一些头结点信息在数组中,因此为了兼容不同的实现,防止OutOfMemoryError,所以特意将int的最大值减去8
4.构造方法
/**
* 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];
}
构造方法:一个无参,一个设置初始化容量的有参构造方法
5.成员方法:
a.length()
返回当前字符的长度,也就是上面提及的count成员变量的值
/**
* Returns the length (character count).
*
* @return the length of the sequence of characters currently
* represented by this object
*/
@Override
public int length() {
return count;
}
b.capacity()
返回的是当前char[]数组的容量,也就是char数组的长度
/**
* Returns the current capacity. The capacity is the amount of storage
* available for newly inserted characters, beyond which an allocation
* will occur.
*
* @return the current capacity
*/
public int capacity() {
return value.length;
}
c.ensureCapacity(int minimumCapacity)
当前方法是为了确保容量等于指定最小值:
public void ensureCapacity(int minimumCapacity) {
//判断minimumCapacity必须是大于零才会有操作
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
//同样的溢出判断
//只有当当前容量大于现在数组的长度时才会进行操作
if (minimumCapacity - value.length > 0) {
//将新数组复制给原来的数组
value = Arrays.copyOf(value,
//扩容操作
newCapacity(minimumCapacity));
}
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private int newCapacity(int minCapacity) {
// overflow-conscious code
//首先扩容为原来的两倍+2
int newCapacity = (value.length << 1) + 2;
//如果此时容量还比设定的最小量小
if (newCapacity - minCapacity < 0) {
//直接将最小量设置成新容量
newCapacity = minCapacity;
}
//如果新容量小于等于0或者当前新容量比MAX_ARRAY_SIZE还大,则调用hugeCapacity(int minCapacity)
//否则就直接是新容量
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
//如果当前新容量超过int最大值
//直接抛出异常
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
//如果没有超过
//则放回当前minCapacity和MAX_ARRAY_SIZE的最大值
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
d.trimToSize()
让空间更有效率,减去空余的空间容量,让实际的长度和数组长度相同
/
* 如果存在维护的数组value的长度比已经使用的容量大
* 那么直接建一个新的数组长度和count一样
* 并赋值给原来的value字节数组
*/
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
}
e.setLength(int newLength)
重新设置成员变量count的长度
/
1.首先会对传进来的长度判负,直接抛异常
* 2.如果当前长度大于新的长度,那么直接按照新的长度来赋值
* 3,如果当前长度小于新的长度,那么按照新的长度,不够的直接用null来代替
*
* @param newLength the new length
* @throws IndexOutOfBoundsException if the
* {@code newLength} argument is negative.
*/
public void setLength(int newLength) {
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength);
if (count < newLength) {
Arrays.fill(value, count, newLength, '\0');
}
count = newLength;
}
f.charAt(int index)
/
* 1.返回当前指定下标的字节char值
* 2.若超过数组下标范围会直接抛异常
*
*/
@Override
public char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}
g.codePointAt(int index)
返回当前下标处字符的代码点
/1.同样的当所给的下标索引超过实际数组范围 抛出异常
* 2.返回指定下标处字符的代码点
*/
public int codePointAt(int index) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointAtImpl(value, index, count);
}
h.codePointBefore(int index)
返回当前下标前一处字符的代码点
/1.同样的当所给的下标索引前一个超过实际数组范围 抛出异常
* 2.返回指定下标处前一个字符的代码点
*/
public int codePointBefore(int index) {
int i = index - 1;
if ((i < 0) || (i >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointBeforeImpl(value, index, 0);
}
i.codePointCount(int beginIndex, int endIndex)
返回给定范围内代码点的数量
/* 1.返回给定范围内的代码点的数量
* 2.超过边界或者后面那个数字大于前面那个数字都会抛出异常
*/
public int codePointCount(int beginIndex, int endIndex) {
if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
return Character.codePointCountImpl(value, beginIndex, endIndex-beginIndex);
}
j.offsetByCodePoints(int index, int codePointOffset)
返回给定索引偏移量位置的索引值
/1.超过边界的位置的位置会抛出异常
* 2.返回给定索引偏移量位置的索引值
*/
public int offsetByCodePoints(int index, int codePointOffset) {
if (index < 0 || index > count) {
throw new IndexOutOfBoundsException();
}
return Character.offsetByCodePointsImpl(value, 0, count,
index, codePointOffset);
}
k.getChars(int srcBegin,int srcEnd,char[] dst, int dstBegin)
给定字节数组,将指定范围的字节赋值到给定数组中
/
* 1.确定边界条件,首先开始和结束都不能是负数,其次结束的值必须大于实际长度count
* ,最后结束的值要大于开始的值,违反以上情况都会抛出异常
* 2.将当前的值赋值到指定的dst字节数组中
*/
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);
}
l.setCharAt(int index , char ch)
将指定索引的char值更换成指定的ch
/1.判断给定索引的值是否超过范围边界,否则抛出异常
* 2.将指定索引的char值更换为ch
*/
public void setCharAt(int index, char ch) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
value[index] = ch;
}
m.append()(这里就不在一一赘述,有很多重载的方法,意思差不多)
将给定的值追加到当前的字符后,返回当前的类型
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
n.delete(int start,int end)
移除给定范围的字节后,返回当前值
/1.判断边界条件,不符合要求的直接抛异常,这里有一点,当end值超过count时,
* 直接被count赋值,意味着移除索引值不得超过实际长度
* 2.移除给定范围的字符后,放回当前的值
*/
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;
}
o.appendCodePoint(int codePoint)
/向原来的值中添加一个代码点
*/
public AbstractStringBuilder appendCodePoint(int codePoint) {
final int count = this.count;
if (Character.isBmpCodePoint(codePoint)) {
ensureCapacityInternal(count + 1);
value[count] = (char) codePoint;
this.count = count + 1;
} else if (Character.isValidCodePoint(codePoint)) {
ensureCapacityInternal(count + 2);
Character.toSurrogates(codePoint, value, count);
this.count = count + 2;
} else {
throw new IllegalArgumentException();
}
return this;
}
p.deleteCharAt(int index)
/* 1.不符合边界调节的索引值直接抛异常
* 2.删除掉指定索引的char值,返回当前值
*/
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;
}
q.replace(int start ,int end,String str)
把指定范围的值替换成str
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插入数组指定位置
str.getChars(value, start);
//更新实际长度值
count = newCount;
return this;
}
r.substring(int start) 和subSequence(int start,int end)
根据索引值返回对应的值,(最后都是new String)
public String substring(int start) {
return substring(start, count);
}
public CharSequence subSequence(int start, int end) {
return substring(start, 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);
}
s.insert()系列,能直接加的就直接加,不能直接加的都是通过String.valueOf()得到string,最终得到字节数组之后添加
public AbstractStringBuilder insert(int offset, Object obj) {
return insert(offset, String.valueOf(obj));
}
public AbstractStringBuilder insert(int offset, String str) {
if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset);
if (str == null)
str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
str.getChars(value, offset);
count += len;
return this;
}
t.indexOf()
返回指定字符串对应的索引值,没有返回-1
public int indexOf(String str) {
return indexOf(str, 0);
}
public int indexOf(String str, int fromIndex) {
return String.indexOf(value, 0, count, str, fromIndex);
}
u.lastIndexOf
存在多个str字符串,返回最后一个字符串所出现的第一个字符的索引值,若不存在直接返回-1
public int lastIndexOf(String str) {
return lastIndexOf(str, count);
}
public int lastIndexOf(String str, int fromIndex) {
return String.lastIndexOf(value, 0, count, str, fromIndex);
}
p.reverse()
反转字符串
/ * 将当前字符串反转
*/
public AbstractStringBuilder reverse() {
//判断是否存在代理
boolean hasSurrogates = false;
int n = count - 1;
//遍历所有数组
//对半遍历,中间的保持不变
for (int j = (n-1) >> 1; j >= 0; j--) {
//k所对应的索引值n-j
int k = n - j;
//互换j和k的值
char cj = value[j];
char ck = value[k];
value[j] = ck;
value[k] = cj;
//判断是否存在代理对
if (Character.isSurrogate(cj) ||
Character.isSurrogate(ck)) {
hasSurrogates = true;
}
}
//如果存在代理
if (hasSurrogates) {
//对代理配进行有效的反转
reverseAllValidSurrogatePairs();
}
//
return this;
}
//反转有效的所有代理配
private void reverseAllValidSurrogatePairs() {
for (int i = 0; i < count - 1; i++) {
char c2 = value[i];
if (Character.isLowSurrogate(c2)) {
char c1 = value[i + 1];
if (Character.isHighSurrogate(c1)) {
value[i++] = c1;
value[i] = c2;
}
}
}
}
q.toString()
抽象方法,等子类实现
public abstract String toString();
r.getValue()
final.看看就好.
final char[] getValue() {
return value;
}
6.总结
基本上抽象类,没更多的实现,大体是规范String类的一些基础操作,中间过程如果有些地方写的不够详细,甚至有错误的地方.欢迎大家进行激烈的探讨,小编也想在茫茫源码中,找寻有志之士.