[源码分析]AbstractStringBuilder

[源码分析]AbstractStringBuilder

Java中, AbstractStringBuilder是 StringBuilder 和 StringBuffer 的父类. 因此了解StringBuilder和StringBuffer前, 有必要先了解一下这个抽象父类.html

这里附上另外两篇文章的链接:java

StringBuilder : http://www.cnblogs.com/noKing/p/jdk8_StringBuilder.html数组

StringBuffer : http://www.cnblogs.com/noKing/p/9431618.html app

value字段

在这里存储字符串内容源码分析

构造器

在构造器内当即建立一个capacity大小的数组, 做为value字段的值.ui

扩容

 每次插入类的操做都会确保空间大小足够. 若是不够就会扩容, 再插入.spa

扩容是靠调用这个方法, 来确保每次有足够的空间.3d

也就是说扩容后具体是多大, 还要根据newCapacity这个方法来定:指针

  能够看到, 扩容策略是原先的数组长度乘以2, 而后加2. htm

若是oldLength*2+2 以后的大小足够大了, 那么下次的数组大小就是这个数值了.

可是oldLength*2+2以后的大小仍是不够, 那么就直接采用传进来的数据做为目标大小.(先不讨论hugeCapacity)

trimToSize

trimToSize的使用结果以下:

public class AbstractStringBuilderTest {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        sb.append("hello");
        System.out.println("size:" + sb.length()); // 5
        System.out.println("capacity" + sb.capacity()); // 16
        sb.trimToSize();
        System.out.println("size:" + sb.length()); // 5
        System.out.println("capacity" + sb.capacity()); // 5
    }
}

setLength方法

详细注意事项用下面的例子来讲明:

public class AbstractStringBuilderTest {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        sb.append("hello");
        System.out.println(sb.toString()); // hello
        System.out.println("size:" + sb.length()); // 5
        System.out.println("capacity" + sb.capacity()); // 16
        sb.setLength(2);
        System.out.println(sb.toString()); // he
        System.out.println("size:" + sb.length()); // 2
        System.out.println("capacity" + sb.capacity()); // 16
        sb.setLength(20);
        System.out.println(sb.toString()); // he\0\0\0\00\0\0\00\0\0\00\0\0\0\0\0
        System.out.println("size:" + sb.length()); // 20
        System.out.println("capacity" + sb.capacity()); // 34
        sb.setLength(77);
        System.out.println("size:" + sb.length()); // 77
        System.out.println("capacity" + sb.capacity()); // 77
    }
}

  在上面这个demo中, 我用到了三次setLength. 可是每次调用后的结果都多多少少有些区别.

第1次调用: 由于setLength的参数比当前字符串的长度要小, 因此字符串被截短了, 长度也直接变为了相应的数值.

第2次调用: 由于setLength的参数比当前字符串的长度要大, 因此多余出来的部分用'\0'来补充.length是20. 而数组进行一次扩容就能够hold住20这个大小, 因此就进行一次正常的扩容就好了. 正常的扩容就是原来的长度乘以2, 而后再加2, 因此是34.

第三次调用: 当前数组的长度是34, 而我setLength的参数是77.  34进行一次扩容才只是34*2+2 = 70. 由于77大于这个70, 因此capacity也就是77了.

 

一样是参数大于当前数组的大小, 一样是用'\0'来补充. 可是若是这个参数太大, 以致于一次扩容没法hold住这个大小, 那么capacity就会直接设置为那个数值.

这段逻辑在newCapacity方法中. 代码前面将扩容的时候粘贴过了.

charAt方法

咱们能够看到charAt就是判断数组越界, 来抛出异常.

返回值直接就是用的数组的下角标.

根据这个, setCharAt方法就不用多说了, 也是判断是否越界, 而后给数组的相应位置赋值.

append方法

append方法的不少重载就是靠调用getChars方法来达到尾插的目的的. 很简单, 就不提了.

就是appendNull方法, 很想吐槽...看完了眼前一亮....

嗯...还有append方法的bool型重载:

.....

substring

能够看到substring底层是直接调用的new String

reverse方法

两个指针j和k. 关于中心对称. 从中间开始一边向两边遍历, 一边交换. 就完成了翻转.

总结

这个类没什么特别的, 但仍是稍微总结一下

1. 构造器里当即初始化数组

2. 扩容方式为 扩容前长度 * 2 + 2

3. 当前第2条说的不严谨. 首先想一想为何扩容呢? 由于插入一个字符串的时候, 剩余空间不足了, 因此扩容. 若是插入的这个字符串太长, 致使扩容一次也没法容纳下呢? 那么就直接把长度设置为 扩容前长度+ 插入的字符串长度 .

4. 大规模使用了System.arraycopy方法.

相关文章
相关标签/搜索