java1.8源码阅读----AbstractStringBuilder

AbstractStringBuilder是一个抽象类,它的两个子类为StringBuffer和StringBuilder。它实现的接口CharSequence和Appendable。

实现的接口

  1. CharSequence:在String类源码分析中已经解释。
  2. Appendable接口:该接口里面只有三个方法,三个方法只有参数不相同,方法名都是一样的。

    Appendable append(char c):将指定的字符附加到此 Appendable 。
    Appendable append(CharSequence csq):将指定的字符序列追加到此 Appendable 。
    Appendable append(CharSequence csq, int start, int end):将指定的字符序列的子序列附加到此 Appendable 。

成员变量

char[] value;
int count;

这两个成员变量一个是用来存储字符,一个是用来记录存储了多少个字符,String类也是用一个char数组存储字符。

构造方法

    /**
     * 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];
    }

该抽象类有两个构造方法,一个午餐构造方法和一个有参构造方法,有参构造方法传了一个int类型的参数,初始化成员变量value的容量。后续有个方法有关系。

具体方法

(1)

    @Override
    public int length() {
        return count;
    }

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

这两个方法,第一个是返回记录存储了多少个字符,第二个是返回成员变量value的容量(因为构造方法可以初始化改成员变量value的容量大小,所以用这两个方法区别开来)
(2)

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

   /**
    * This method has the same contract as ensureCapacity, but is
    * never synchronized.
    */
   private void ensureCapacityInternal(int minimumCapacity) {
       // overflow-conscious code
       if (minimumCapacity - value.length > 0)
           expandCapacity(minimumCapacity);
   }

   /**
    * This implements the expansion semantics of ensureCapacity with no
    * size check or synchronization.
    */
   void expandCapacity(int minimumCapacity) {
       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);
   }

   /**
    * Attempts to reduce storage used for the character sequence.
    * If the buffer is larger than necessary to hold its current sequence of
    * characters, then it may be resized to become more space efficient.
    * Calling this method may, but is not required to, affect the value
    * returned by a subsequent call to the {@link #capacity()} method.
    */
   public void trimToSize() {
       if (count < value.length) {
           value = Arrays.copyOf(value, count);
       }
   }
   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;
   }

上面五个方法都跟缓冲区有关。
ensureCapacity(int minimumCapacity):确保容量至少等于指定的最小值。如果当前容量小于参数,则分配一个新的具有更大容量的内部数组。他的具体实现调用的下面的方法ensureCapacityInternal(int minimumCapacity)。这两个方法总体来说,首先传递一个int类型minimumCapacity,判断该参数是否大于0,大于零调用ensureCapacityInternal(int minimumCapacity),该方法用
minimumCapacity去与value.length相减,如果大于零则数组扩容minimumCapacity大小,否则取原value大小。

expandCapacity(int minimumCapacity):该方法也是扩容,但不需要检查minimumCapacity是否大于或者小于0,它的实现首先初始化一个大小为value.length * 2 + 2的值,然后与minimumCapacity相减,如果小于0说明minimumCapacity大于value.length * 2 + 2,容量值大小取minimumCapacity,否则取value.length * 2 + 2,最后如果这两个值都小于0,则初始化容量大小为Integer.MAX_VALUE。

trimToSize():试图减少用于字符序列的存储。如果缓冲区大于容纳当前字符序列所需的大小,则可以调整大小以提高空间效率。调用此方法可能(但不是必需的)影响后续调用capacity()方法返回的值。

setLength(int newLength):设置字符序列的长度。将序列更改为一个新的字符序列,其长度由参数指定。对于每一个小于newLength的非负索引k,如果k小于旧字符序列的长度,则新字符序列中索引k处的字符与旧字符序列中索引k处的字符相同;否则,它就是空字符’\u0000’。换句话说,如果newLength参数小于当前长度,则将该长度更改为指定的长度。
如果newLength参数大于或等于当前l(有道翻译)
从实现可以看出当newLength<0时,抛出一个StringIndexOutOfBoundsException(newLength),然后调用ensureCapacityInternal(newLength)(不管newLength>0或者小于0都会调用),因为newLength<0所有取原来数组。如果
count < newLength调用的 Arrays.fill(value, count, newLength, ‘\0’);

    public static void fill(char[] a, int fromIndex, int toIndex, char val) {
        rangeCheck(a.length, fromIndex, toIndex);
        for (int i = fromIndex; i < toIndex; i++)
            a[i] = val;
    }

该方法是从a下标索引fromIndex开始到toIndex下标的字符替换成val

(3)
public AbstractStringBuilder append(String str):该方法先判断str是否为null,如果为null,则在调用该方法对象中加入null字符数组。如果不为空,先初始化该对象的容量,利用String类里面的getChars方法把str加到该对象后面。其余的是重载的参数不同。

    public AbstractStringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }
    public AbstractStringBuilder append(StringBuffer sb) {
        if (sb == null)
            return appendNull();
        int len = sb.length();
        ensureCapacityInternal(count + len);
        sb.getChars(0, len, value, count);
        count += len;
        return this;
    }
    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;
    }
     private AbstractStringBuilder appendNull() {
        int c = count;
        ensureCapacityInternal(c + 4);
        final char[] value = this.value;
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l';
        count = c;
        return this;
    }

public AbstractStringBuilder append(CharSequence s):该方法重写Appendable里面的方法。看源码也不是很难理解。
注意:在该类中凡是改变了value的值,count也要随着变化。

    @Override
   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());
   }
   @Override
   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 += len;
       return this;
   }

ps:关于instanceof:

子类 instanceof 父类 == true
父类 instanceof 子类 == false

其余的append(param)实现的方法都差不多。 public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length):这个方法真的很好用,源码里面这个方法出现的次数很多,对数组进行缩容和扩容很好用。
(4)

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

delete(int start, int end):删除此序列子字符串中的字符。子字符串从指定的开始处开始,并扩展到索引末尾- 1处的字符,如果不存在这样的字符,则扩展到序列末尾。如果开始等于结束,则不做任何更改。
都是利用System.arraycopy方法进行缩容
(5)

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

public AbstractStringBuilder replace(int start, int end, String str):用指定字符串中的字符替换此序列子字符串中的字符。子字符串从指定的开始处开始,并扩展到索引末尾- 1处的字符,如果不存在这样的字符,则扩展到序列末尾。首先删除子字符串中的字符,然后在开始处插入指定的字符串。(如果需要,这个序列将被加长以适应指定的字符串。)
该方法实现也是利用System.arraycopy方法进行数组操作,最后在把给的字符串参数加到指定位置。
(5)

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

public AbstractStringBuilder insert(int dstOffset, CharSequence s,int start, int end):将指定字符序列的子序列插入到此序列中。按顺序,将start和end指定的参数s的子序列插入到指定目标偏移量处的序列中,向上移动最初位于该位置之上的任何字符。这个序列的长度由结束-开始递增
从实现源码来看,首先进行参数校验,然后在求出复制后数组的大小,最后替换指定范围类为替换的字符串。
改方法有很多重载方法,无非是转换成调用这个所要的参数来实现的。
(6)

    public AbstractStringBuilder reverse() {
        boolean hasSurrogates = false;
        int n = count - 1;
        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;
    }

    /** Outlined helper method for reverse() */
    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;
                }
            }
        }
    }

public AbstractStringBuilder reverse() :将此字符序列替换为该序列的反面。如果序列中包含任何代理对,则将这些代理对视为反向操作的单个字符。因此,高-低代位体的顺序永远不会颠倒。设n是这个字符序列的字符长度(不是char值中的长度),刚好在执行反向方法之前。那么新字符序列中下标k处的字符就等于旧字符序列中下标n-k-1处的字符。
注意,反向操作可能导致生成代理
Character源码没有阅读,以后再反过来补充下。
总结:该抽象类主要有两个实现类,提供了一下操作字符数组的方法:append,insert,charAt,subString,reverse,indexOf等方法。要注意的是该类的扩容机制。并且该类权限默认friendly 。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值