AbstractStringBuilder源码解析

 

abstract class AbstractStringBuilder implements Appendable, CharSequence 

抽象类,实现列Appendable和CharSequence

属性

value

char[] value;

该值用于字符存储。没加final这也是为什么StringBuffer、StringBuilder说是可变的原因

count

int count
计数是使用的字符数

MAX_ARRAY_SIZE

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

当前value数组的最大容量

构造方法

AbstractStringBuilder

AbstractStringBuilder() {
}

这个无参数构造函数对于子类的序列化是必需的。

AbstractStringBuilder(int capacity)

AbstractStringBuilder(int capacity) {
        value = new char[capacity];
}

创建指定容量的AbstractStringBuilder。

 

方法&函数

length()

public int length() {
     return count;
}

返回长度(字符数)

capacity()

public int capacity() {
     return value.length;
}

返回当前容量。容量是可用于新插入字符的存储量,超过该容量将发生分配。

ensureCapacity(int minimumCapacity)

public void ensureCapacity(int minimumCapacity) {
        if (minimumCapacity > 0)
            ensureCapacityInternal(minimumCapacity);
}

这和value数组扩容有关系。如果当前数组小于该参数指定的容量,那么就发生扩容。(PS:还是调用了  ensureCapacityInternal 方法)

ensureCapacityInternal(int minimumCapacity) 

private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
}

用的是Arrays.copyOf这个方法扩容数组。

 

newCapacity(int minCapacity)

 private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
}

就是返回当前需要扩容的容量。 如果新的容量小于0或者 大于最大扩容量就调用 hugeCapacity(minCapacity)方法

PS:关于 << 运算符号,可以理解为前数乘以2的后数次方

hugeCapacity(int minCapacity) 

 private int hugeCapacity(int minCapacity) {
//如果扩容量大于Integer.MAX_VALUE那么就抛异常。
        if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
            throw new OutOfMemoryError();
        }  
      return (minCapacity > MAX_ARRAY_SIZE)
            ? minCapacity : MAX_ARRAY_SIZE;
 }

 trimToSize()

public void trimToSize() {
        if (count < value.length) {
            value = Arrays.copyOf(value, count);
        }
 }

尝试减少用于字符序列的存储空间。 如果缓冲区大于保持其当前字符序列所需的缓冲区,则可以调整其大小以提高空间效率。

setLength(int newLength)

 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;
 }

设置字符序列的长度。 序列更改为新的字符序列,其长度由参数指定。

解释片段

Arrays.fill(value, count, newLength, '\0');

fill方法:从count开始,到newLength结束填充 指定的char值(这里是'\0')到value数组里面去

charAt(int index)

 public char charAt(int index) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        return value[index];
}

返回指定索引处的char值

codePointAt(int index)

public int codePointAt(int index) {
        if ((index < 0) || (index >= count)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointAtImpl(value, index, count);
}

返回指定索引处的字符(Unicode代码点)。索引引用char值

 

codePointBefore(int index)

public int codePointBefore(int index) {
        int i = index - 1;
        if ((i < 0) || (i >= count)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointBeforeImpl(value, index, 0);
}

返回指定索引前的Unicode代码点。

codePointCount

public int codePointCount(int beginIndex, int endIndex) {
        if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
            throw new IndexOutOfBoundsException();
        }
        return Character.codePointCountImpl(value, beginIndex, endIndex-beginIndex);
 }

返回此序列的指定文本*范围内的Unicode代码点数

getChars(int srcBegin, int srcEnd, char[] dst, int 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);
}

这是一个从对象的value数字里面吧指定字符复制到目标数组的方法。

srcBegin 复制value数组的启始位置

srcEnd 复制value数组的结束位置

dst 复制的指定数组

dstBegin 指定数字的起始复制位置

setCharAt(int index, char ch)

 public void setCharAt(int index, char ch) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        value[index] = ch;
}

这个就不解释啦

结下了我们来看看append方法然后实现

append(String str)

  public AbstractStringBuilder append(String str) {
        //判读str是不是null
        if (str == null)
//            appendNull就是在该value数字的后面加上一个null字符串
            return appendNull();
        //获取str字符串的长度
        int len = str.length();
        //调用这个方法是为了看看要不要扩容
        ensureCapacityInternal(count + len);
        //调用字符串的grtChars方法把 str字符串中的value数字拷贝到该对象的value数字中
        str.getChars(0, len, value, count);
        //count 增加对于长度
        count += len;
        //返回apppend后的该对象
        return this;
}

就解释这个一个,其他的append套路都一样,只是参数不同而已

 

append(CharSequence s, int start, int end)

 public AbstractStringBuilder append(CharSequence s, int start, int end) {
        if (s == null)
            s = "null";
        //如果给定区间有问题那么就抛出异常
        if ((start < 0) || (start > end) || (end > s.length()))
            throw new IndexOutOfBoundsException(
                    "start " + start + ", end " + end + ", s.length() "
                            + s.length());
        //给的区间的字符数
        int len = end - start;
        //看看要不要扩容呀
        ensureCapacityInternal(count + len);
        //使用循环添加指定区间的字符
        for (int i = start, j = count; i < end; i++, j++)
            value[j] = s.charAt(i);
        //把添加后的字符串长度赋值给count
        count += len;
        //返回该对象
        return this;
}

其他的append方法就不解析啦哈,那些我相信对于你已经没有啥太大的难度啦。加油!!

append(int i)

public AbstractStringBuilder append(int i) {
        //如果 i等于Integer.MIN_VALUE 那么久直接添加该值对应的字符串。
//        这样干的原因是因为和int取值范围有关
        if (i == Integer.MIN_VALUE) {
            append("-2147483648");
            return this;
        }
        //获得该int类型的长度
        int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
                : Integer.stringSize(i);
        //当添加完该int值后新字符串的长度
        int spaceNeeded = count + appendedLength;
        //通知扩容方法,是否进行扩容
        ensureCapacityInternal(spaceNeeded);
        //调用Integer.getChar方法把i的转换为字符,复制到 value数字里面
        Integer.getChars(i, spaceNeeded, value);
        //刷新当前字符数
        count = spaceNeeded;
        return this;
}

appendNull()

 private AbstractStringBuilder appendNull() {
        int c = count;
//        如果加上null以后是否需要扩容
        ensureCapacityInternal(c + 4);
        final char[] value = this.value;
        //添加null字符串
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l';
//        把现在的长度赋值给count
        count = c;
        return this;
}

delete(int start, int end) 

    public AbstractStringBuilder delete(int start, int end) {
        if (start < 0)
            //开始位置小于0抛异常
            throw new StringIndexOutOfBoundsException(start);
        if (end > count)
            //结束位置大于字符数组中的字符总数,那么就最多只能给截到最后一位
            end = count;
        if (start > end)
            //开始位置大于结束位置报错
            throw new StringIndexOutOfBoundsException();
        //计算要删除字符的总数
        int len = end - start;
        if (len > 0) {
          //  使用arraycopy方法把删除位置后的字符覆盖被删除位置上的字符
            System.arraycopy(value, start+len, value, start, count-end);
           //删除后的字符总数重新计算
            count -= len;
        }
   // 返回该对象本身
        return this;
    }


deleteCharAt(int 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;
 }

删除指定位置的 字符

replace(int start, int end, String 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);
        /**
         * src:源数组; 
           srcPos:源数组要复制的起始位置; 
           dest:目的数组; 
           destPos:目的数组放置的起始位置; 
           length:复制的长度。 
           注意:src and dest都必须是同类型或者可以进行转换类型的数组.
         */
        System.arraycopy(value, end, value, start + len, count - end);
        //把str字符串复制到value数组中,从start中开始向后一个一个字符的复制
        str.getChars(value, start);
        //从新设置当前的count
        count = newCount;
        return this;
    }

 

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);
}

截取指定位置字符。返回字符串。

 

insert(int index, char[] str, int offset, int len)

 

  public AbstractStringBuilder insert(int offset, char[] str) {
        //超出范围抛异常
        if ((offset < 0) || (offset > length()))
            throw new StringIndexOutOfBoundsException(offset);
        //获取当前str数组的长度
        int len = str.length;
        //通知扩容方法看看新的字符数组是否装得下
        ensureCapacityInternal(count + len);
        //先将原数组移动指定位置,好让str插入进来
        System.arraycopy(value, offset, value, offset + len, count - offset);
        //把str从指定位置插入到数组中去
        System.arraycopy(str, 0, value, offset, len);
        //更新count
        count += len;
        return this;
}

insert(int dstOffset, CharSequence s,int start, int end)

public AbstractStringBuilder insert(int dstOffset, CharSequence s,
                                        int start, int end) {
        if (s == null)
            s = "null";
        if ((dstOffset < 0) || (dstOffset > this.length()))
            throw new IndexOutOfBoundsException("dstOffset "+dstOffset);
        if ((start < 0) || (end < 0) || (start > end) || (end > s.length()))
            throw new IndexOutOfBoundsException(
                    "start " + start + ", end " + end + ", s.length() "
                            + s.length());
        //s要插入的部分长度
        int len = end - start;
        ensureCapacityInternal(count + len);
        //原数组调整。已便于插入
        System.arraycopy(value, dstOffset, value, dstOffset + len,
                count - dstOffset);
        //循环传入字符到数组中去
        for (int i=start; i<end; i++)
            value[dstOffset++] = s.charAt(i);
        count += len;
        return this;
    }

AbstractStringBuilder reverse()

public AbstractStringBuilder reverse() {
        //首先设为false
        boolean hasSurrogates = false;
        int n = count - 1;
        //(n -1) >> 1 就相当于 (n - 1) / 2, n - 1的原因是因为中间那一位不需要反转
        for (int j = (n-1) >> 1; j >= 0; j--) {
            /**
             * k 对于数组右边的字符索引
             *j 对于数组左边的字符索引
             */
            int k = n - j;
            char cj = value[j];
            char ck = value[k];
            //左右位置交换
            value[j] = ck;
            value[k] = cj;
            /*
             *  Character 要判断每个字符是否在
             *  Character.MIN_SURROGATE(\ud800)
             *  和Character.MAX_SURROGATE(\udfff)之间
             */
           if (Character.isSurrogate(cj) ||
                    Character.isSurrogate(ck)) {
                hasSurrogates = true;
            }
        }

        if (hasSurrogates) {
            reverseAllValidSurrogatePairs();
        }
        return this;
    }

至于为什么要Character.isSurrogate() 参考博客:https://www.cnblogs.com/wanlipeng/archive/2011/01/27/1946441.html

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值