[源码分析]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()); // 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方法.

[源码分析]AbstractStringBuilder的更多相关文章

  1. [源码]String StringBuffer StringBudlider(2)StringBuffer StringBuilder源码分析

      纵骑横飞 章仕烜   昨天比较忙 今天把StringBuffer StringBulider的源码分析 献上   在讲 StringBuffer StringBuilder 之前 ,我们先看一下 ...

  2. String、StringBuffer、StringBuilder源码分析

    利用反编译具体看看"+"的过程 1 public class Test 2 { 3 public static void main(String[] args) 4 { 5 int ...

  3. [源码分析]StringBuilder

    [源码分析]StringBuilder StringBuilder是继承自AbstractStringBuilder的. 这里附上另外两篇文章的连接: AbstractStringBuilder :  ...

  4. [源码分析]StringBuffer

    [源码分析]StringBuffer StringBuffer是继承自AbstractStringBuilder的. 这里附上另外两篇文章的连接: AbstractStringBuilder : ht ...

  5. String,StringBuffer,StringBuilder源码分析

    1.类结构 String Diagrams StringBuffer Diagrams StringBuilder Diagrams 通过以上Diagrams可以看出,String,StringBuf ...

  6. String 类源码分析

    String 源码分析 String 类代表字符序列,Java 中所有的字符串字面量都作为此类的实例. String 对象是不可变的,它们的值在创建之后就不能改变,因此 String 是线程安全的. ...

  7. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  8. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  9. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

随机推荐

  1. java:数据结构(二)栈的应用(进制转换全收集)

    说到进制转换,java已经封装了基本的方法,在竞赛中使用封装的方法自然能节省大量时间 另一位仁兄介绍的封装好的方法: https://blog.csdn.net/m0_37961948/article ...

  2. MyDAL - .QueryListAsync() 使用

    索引: 目录索引 一.API 列表 .QueryListAsync() .QueryListAsync<M>() 如: .QueryListAsync<AgentInventoryR ...

  3. Delphi中使用ISuperObject解析Json数据

    Java.Php等语言中都有成熟的框架来解析Json数据,可以让我们使用很少的代码就把格式化好的json数据转换成程序可识别的对象或者属性,同时delphi中也有这样的组件来实现此功能,即Isuper ...

  4. C# -- 使用 DriveInfo 获取磁盘驱动器信息

    C# -- 使用 DriveInfo 获取磁盘驱动器信息 1. 代码实现 class Program { static void Main(string[] args) { GetComputerDi ...

  5. RocketMQ4.3.X关于设置useEpollNativeSelector = true报错问题

    前一阵子刚整理完RocketMQ4.3.x版本的相关配置的工作,接下来就来测试一下改变参数会带来什么好的结果 首先我就选中了useEpollNativeSelector 这个参数 默认这个参数是 fa ...

  6. Fiddler-抓取手机app请求

    如何使用 Fiddler 抓取手机app请求? 前提:手机和电脑在同一局域网 1.设置 Fiddler>Tools>Options>Connections 勾选 Allow remo ...

  7. 逆向-攻防世界-logmein

    iDA载入程序,shift+F12查看关键字符串,找到双击来到所在地址,进入函数 然后进入主函数, 经过分析,可以得出:输入的字符要等于  经过处理的v7和v8的异或.v8很明显,但是v7是怎么回事呢 ...

  8. 类System

    System类简介: 在 System 类中提供了大量的静态方法,有标准输入.标准输出和错误输出流:对外部定义的属性和环境变量的访问:加载文件和库的方法:还有快速复制数组的一部分的实用方法. 常用方法 ...

  9. flex.css

    flex.css:https://codepen.io/webstermobile/pen/apXEER/

  10. protobuf使用详解

    https://blog.csdn.net/skh2015java/article/details/78404235 原文地址:http://blog.csdn.net/lyjshen/article ...