zoukankan      html  css  js  c++  java
  • [源码分析]AbstractStringBuilder

    [源码分析]AbstractStringBuilder

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

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

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

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

    value字段

    在这里存储字符串内容

    构造器

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

    扩容

     每次插入类的操作都会确保空间大小足够. 如果不够就会扩容, 再插入.

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

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

      可以看到, 扩容策略是原先的数组长度乘以2, 然后加2. 

    如果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()); // he000
            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的参数比当前字符串的长度要大, 所以多余出来的部分用''来补充.length是20. 而数组进行一次扩容就可以hold住20这个大小, 所以就进行一次正常的扩容就行了. 正常的扩容就是原来的长度乘以2, 然后再加2, 所以是34.

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

    同样是参数大于当前数组的大小, 同样是用''来补充. 但是如果这个参数太大, 以至于一次扩容无法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方法.

  • 相关阅读:
    文档浏览类的网站该如何设计?
    如何将动态生成Word文件
    Word 2007 文档结构图混乱
    Spring 配置 Spring JPA 发生错误的解决方法
    今天开始着手原来Office系统的重构
    Jetty入门
    推荐一个C语言学习教程
    博客园的第一天
    我与solr(一)--solr的配置与安装
    XML解析工具类
  • 原文地址:https://www.cnblogs.com/noKing/p/9427967.html
Copyright © 2011-2022 走看看