java.lang.*中AbstractStringBuilder 源代码详解

java.lang.*中AbstractStringBuilder 源代码详解

    • 核心方法
    • AbstractStringBuilder()构造方法
    • int length()
    • int capacity()
    • void ensureCapacity()
    • void trimToSize()
    • void setLength()
    • char charAt()
    • int codePointAt()
    • int codePointBefore()
    • int codePointCount()
    • int offsetByCodePoints()
    • void getChars()
    • void setCharAt()
    • AbstractStringBuilder append()
    • AbstractStringBuilder delete()
    • AbstractStringBuilder appendCodePoint()
    • AbstractStringBuilder deleteCharAt()
    • AbstractStringBuilder replace()
    • AbstractStringBuilder insert()
    • AbstractStringBuilder reverse()

核心方法

AbstractStringBuilder()构造方法[OK]
int length() 获取当前对象的实际长度[OK]
int capacity() 获取当前对象的内存容量长度[OK]
void ensureCapacity() 主动触发扩容动作[OK]
void trimToSize() 释放对象中,未使用的容量内存[OK]
void setLength() 设置当前对象的实际长度,不足用’\0’填充[OK]
char charAt() 获取某个索引位置的字符[OK]
int codePointAt() 返回当前索引位置字符的ASCII值[OK]
int codePointBefore() 返回前一个索引位置字符的ASCII值[OK]
int codePointCount() 返回字符个数[OK]
int offsetByCodePoints() 返回字符个数[OK]
void getChars() 将字符从此序列复制到目标字符数组[OK]
void setCharAt() 设置某个索引位置的字符[OK]
AbstractStringBuilder append() 拼接str字符串[OK]
AbstractStringBuilder delete() 删除[start,end)位置的字符[OK]
AbstractStringBuilder appendCodePoint() 拼接ASCII码对应的int值字符 [OK]
AbstractStringBuilder deleteCharAt() 删除字符序列某个索引位置的值[OK]
AbstractStringBuilder replace() 替换某个索引范围的字符序列[OK]
AbstractStringBuilder insert() 向当前字符的某个索引位置插入字符串[OK]
AbstractStringBuilder reverse() 字符序列的反转[OK]

AbstractStringBuilder()构造方法

/**
 * 这个空参构造函数,是为了让子类可以实现实例化
 */
AbstractStringBuilder() {
}

/**
 * 创建一个固定容量大小的AbstractStringBuilder对象
 * 1.子类StringBuilder默认容量大小为16
 * 2.子类StringBuffer默认容量大小为16
 */
AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

int length()

/**
 *  当前存在于对象中的字符序列长度(实际长度)
 */
@Override
public int length() {
    return count;
}

int capacity()

/**
 *1.获取当前对象的内存容量大小,默认是16
 *2.扩容机制:n*2+2,详情见append方法
 *3.StringBuilder、StringBuffer扩容机制相同
 */
public int capacity() {
    return value.length;
}

void ensureCapacity()

示例:
StringBuilder sr = new StringBuilder();
//不扩容,因为参数minimumCapacity必须大于0,才进入扩展容量逻辑
sr.ensureCapacity(0);
//当前容量为16,而目标为1,不扩容。进入扩展容量逻辑,但当前容量为16,完全可以装下容量1的数据,所以不需要扩容
sr.ensureCapacity(1);
//当前容量为16,而目标为33,扩容一次,当前容量变成16*2+2=34
sr.ensureCapacity(33);
//当前容量为34,而目标为34,不扩容。进入扩展容量逻辑,但当前容量为34,完全可以装下容量34的数据,所以不需要扩容
sr.ensureCapacity(34);
//当前容量为34,而目标为35,扩容一次,当前容量变成35*2+2=70
sr.ensureCapacity(35);

System.out.println(sr.length());
System.out.println(sr.capacity());

结果:
0
70

/**
 * 根据参数,主动触发扩容
 * 1.首先minimumCapacity必须大于0,才进入扩容逻辑
 * 2.minimumCapacity必须大于当前容量,才进入扩容逻辑
 * 3.如果minimumCapacity小于等于当前容量n*2+2的值,就用默认扩容
 * 4.如果minimumCapacity大于当前容量n*2+2的值,用入参进行扩容
 */
public void ensureCapacity(int minimumCapacity) {
    if (minimumCapacity > 0)//判断是否大于0
        ensureCapacityInternal(minimumCapacity);
}

private void ensureCapacityInternal(int minimumCapacity) {
    //判断当前参数是否大于当前容量
    if (minimumCapacity - value.length > 0)
        expandCapacity(minimumCapacity);
}

void expandCapacity(int minimumCapacity) {
    int newCapacity = value.length * 2 + 2;
    //比较计算后的newCapacity与minimumCapacity的大小
    if (newCapacity - minimumCapacity < 0)
        newCapacity = minimumCapacity;
    if (newCapacity < 0) {
        if (minimumCapacity < 0) // overflow
            throw new OutOfMemoryError();  
        newCapacity = Integer.MAX_VALUE;
    }
    //采用Arrays.copyOf方法生成新的char[],此处是浅拷贝
    value = Arrays.copyOf(value, newCapacity);
}

void trimToSize()

/**
 * 释放对象中,未使用的容量内存(并不是立马释放,交给jvm处理垃圾回收)
 * 样例代码:
 * StringBuilder sr = new StringBuilder();
 *
 * System.out.println(sr.length());
 * System.out.println(sr.capacity());
 *
 * sr.append("123456789");
 * sr.trimToSize();
 *
 * System.out.println(sr.length());
 * System.out.println(sr.capacity());
 *
 * 输出结果:
 * 0
 * 16
 * 9
 * 9
 */
public void trimToSize() {
    if (count < value.length) {
        value = Arrays.copyOf(value, count);
    }
}

void setLength()

/**
 * 1.设置当前字符对象的实际长度,不足用'\0'填充
 * 2.newLength可能触发扩容机制
 * 3.注意'\0'不是空格
 * 4.'\0'的ASCII值是0,空格' '字符的ASCII是32
 * 5.String.trim()方法会截取掉'\0'和' '空格字符
 */
public void setLength(int newLength) {
	//判断长度是否合法
    if (newLength < 0)
        throw new StringIndexOutOfBoundsException(newLength);
    ensureCapacityInternal(newLength);
	//如果newLength大于实际存储的字符长度,则向当前字符序列的末尾填充'\0'
    if (count < newLength) {
        Arrays.fill(value, count, newLength, '\0');
    }

    count = newLength;
}

char charAt()

public char charAt(int index) {
	//判断角标是否越界
    if ((index < 0) || (index >= count))
        throw new StringIndexOutOfBoundsException(index);
    return value[index];
}

int codePointAt()

/**
 * 返回当前索引位置字符的ASCII值
 */
public int codePointAt(int index) {
	//判断角标是否越界
    if ((index < 0) || (index >= count)) {
        throw new StringIndexOutOfBoundsException(index);
    }
    return Character.codePointAtImpl(value, index, count);
}

static int codePointAtImpl(char[] a, int index, int limit) {
   char c1 = a[index];
   	//判断是否是Unicode高代理代码单元
    if (isHighSurrogate(c1) && ++index < limit) {
        char c2 = a[index];
        //判断是否是Unicode低代理代码单元
        if (isLowSurrogate(c2)) {
            return toCodePoint(c1, c2);
        }
    }
    return c1;
}

int codePointBefore()

/**
 * 返回当前索引前一个索引位置字符的ASCII值
 */
public int codePointBefore(int index) {
    int i = index - 1;
    if ((i < 0) || (i >= count)) {//检查角标是否越界
        throw new StringIndexOutOfBoundsException(index);
    }
    return Character.codePointBeforeImpl(value, index, 0);
}

static int codePointBeforeImpl(char[] a, int index, int start) {
    char c2 = a[--index];//获取前一个位置的字符
    //判断是否是Unicode低代理代码单元
    if (isLowSurrogate(c2) && index > start) {
        char c1 = a[--index];
        //判断是否是Unicode高代理代码单元
        if (isHighSurrogate(c1)) {
            return toCodePoint(c1, c2);
        }
    }
    return c2;
}

int codePointCount()

/**
 * 返回索引位置[beginIndex,endIndex)内的有效字符数量
 * 非Unicode高代理代码单元
 * 非Unicode低代理代码单元
 */
public int codePointCount(int beginIndex, int endIndex) {
	//判断角标是否越界
    if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
        throw new IndexOutOfBoundsException();
    }
    return Character.codePointCountImpl(value, beginIndex, endIndex-beginIndex);
}

static int codePointCountImpl(char[] a, int offset, int count) {
    int endIndex = offset + count;
    int n = count;
    for (int i = offset; i < endIndex; ) {
    	//如果当前位置字符为Unicode高代理代码单元
    	//且下一个索引位置字符为Unicode低代理代码单元
    	
        if (isHighSurrogate(a[i++]) && i < endIndex &&
            isLowSurrogate(a[i])) {
            n--;//数量减一
            i++;
        }
    }
    return n;
}

int offsetByCodePoints()

/**
 * 与codePointCount方法类似
 * 返回索引位置[index,index+codePointOffset)内的有效字符数量
 * 非Unicode高代理代码单元
 * 非Unicode低代理代码单元
 */ 
public int offsetByCodePoints(int index, int codePointOffset) {
    if (index < 0 || index > count) {
        throw new IndexOutOfBoundsException();
    }
    return Character.offsetByCodePointsImpl(value, 0, count,
                                            index, codePointOffset);
}

static int offsetByCodePointsImpl(char[]a, int start, int count,
                                      int index, int codePointOffset) {
    int x = index;
    if (codePointOffset >= 0) {
        int limit = start + count;
        int i;
        for (i = 0; x < limit && i < codePointOffset; i++) {
            if (isHighSurrogate(a[x++]) && x < limit &&
                isLowSurrogate(a[x])) {
                x++;
            }
        }
        if (i < codePointOffset) {
            throw new IndexOutOfBoundsException();
        }
    } else {
        int i;
        for (i = codePointOffset; x > start && i < 0; i++) {
            if (isLowSurrogate(a[--x]) && x > start &&
                isHighSurrogate(a[x-1])) {
                x--;
            }
        }
        if (i < 0) {
            throw new IndexOutOfBoundsException();
        }
    }
    return x;
}

void getChars()

public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
                              int dstBegin)
{
    super.getChars(srcBegin, srcEnd, dst, dstBegin);
}
/*
 * 将字符从此序列复制到目标字符数组
 * @param      srcBegin   当前字符的索引位置
 * @param      srcEnd     当前字符的结束位置
 * @param      dst        新的char数组
 * @param      dstBegin   新数组开始的索引位置(一般从0开始)
 * 
 * 底层调用的System.arraycopy方法
 * /
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);
}

void setCharAt()

/**
 * 设置某个索引位置的字符
 * @param index 当前字符序列的索引位置
 * @param ch 替换的字符
 */
public void setCharAt(int index, char ch) {
	//判断角标是否越界
    if ((index < 0) || (index >= count))
        throw new StringIndexOutOfBoundsException(index);
    value[index] = ch;
}

AbstractStringBuilder append()

/**
 * 拼接str字符串
 * @param str 待拼接的字符串
 */
public AbstractStringBuilder append(String str) {
	//判断str是否为空,如果为空,拼接null字符
    if (str == null)
        return appendNull();
    int len = str.length();
    //判断是否需要扩容
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

AbstractStringBuilder delete()

/**
 * 删除[start,end)位置的字符
 * @param start 索引开始位置(包含)
 * @param 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) {
    	//核心逻辑,按照内存地址,对value对象进行截取,再赋值给value本身
        System.arraycopy(value, start+len, value, start, count-end);
        //减去中间的长度
        count -= len;
    }
    return this;
}

AbstractStringBuilder appendCodePoint()

/**
 * 拼接ASCII码对应的int值字符
 * @param codePoint拼接字符的ASCII值
 */
public AbstractStringBuilder appendCodePoint(int codePoint) {
    final int count = this.count;

    if (Character.isBmpCodePoint(codePoint)) {
        ensureCapacityInternal(count + 1);
        //将ASCII码值int转成字符97->A
        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;
}

AbstractStringBuilder deleteCharAt()

public synchronized StringBuffer deleteCharAt(int index) {
    toStringCache = null;
    super.deleteCharAt(index);
    return this;
}

/**
  * 删除某个字符序列索引位置的字符(雷同于delete方法)
  * @param index 待删除的索引位置的字符
  */
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;
}

AbstractStringBuilder replace()

/**
 * 测试样例 :
 * StringBuffer sb = new StringBuffer();
        String target = null;
        sb.append("abcde");
        sb.append(target);
   sb.replace(0,1,"AAA");     
 * 替换某个索引范围的字符序列
 * @param      start 当前字符序列的开始索引位置
 * @param      end   当前字符序列的结束索引位置
 * @param      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");
	//如果end>count,默认使用count的值
    if (end > count)
        end = count;
    //新字符串的长度    
    int len = str.length();
    //计算替换后的字符序列大小,分析是否需要扩容
    int newCount = count + len - (end - start);
    ensureCapacityInternal(newCount);
	//abcdnull -> abcbcdnull
    System.arraycopy(value, end, value, start + len, count - end);
    //AAAbcdnull
    str.getChars(value, start);
    count = newCount;
    return this;
}

AbstractStringBuilder insert()

/**
 * 向当前字符的某个索引位置插入字符串
 * 内部实现雷同replace方法
 * 1.采用System.arraycopy
 * 2.采用getChars()
 * @param      offset   插入的索引位置
 * @param      str      待插入的字符串对象
 */
public AbstractStringBuilder insert(int offset, String str) {
	//判断角标是否越界
    if ((offset < 0) || (offset > length()))
        throw new StringIndexOutOfBoundsException(offset);
    //判断字符串对象是否为null
    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;
}

AbstractStringBuilder reverse()

/**
 * 返回一个反转后的字符序列对象
 * @since   JDK1.0.2
 */
@Override
public synchronized StringBuffer reverse() {
    toStringCache = null;
    super.reverse();
    return this;
}

public AbstractStringBuilder reverse() {
    boolean hasSurrogates = false;
    int n = count - 1;
    //算法核心,从中间向两边扩散交换
    //(n-1) >> 1 等同于 (n-1)/2
    for (int j = (n-1) >> 1; j >= 0; j--) {
        int k = n - j;
        //交换对称两个位置的值
        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;
}

学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:543120397 我们一起学Java!

你可能感兴趣的:(源码解读,java)