对StringBuilder的append方法底层详解
首先查看builder对象的初始化
StringBuilder builder = new StringBuilder();
在该方法内指向了超类的构造方法,并传入了一个int值,它的形参名为:容积(capacity)
public StringBuilder() {super(16);//这是一个固定的值
}
- 在创建StringBuilder对象时传入的如果是String类型的话会固定有一个16的长度,即使在创建的时候就定义了一个字符串,在底层创建数组时仍然是 字符串长度+16
- 在数组创建完成后仍然会通过append来将字符串追加到数组中
public StringBuilder(String str) {super(str.length() + 16);append(str);
}
- 唯一的另类就是在初始化对象时,传参传的是int类型的值时,StringBuilder会将该值替换掉默认的容量,以该容量进行数组的初始化
public StringBuilder(int capacity) {super(capacity);
}
跟随该指向我们来到了超类AbstractStringBuilder中
超类中初始定义了一个字符数组value,一个整数count
char[] value; //该数组就是buffer与builder的底层所指向的那个数组int count; //count主要是用来对数组长度进行计数
在该构造方法中,将我们从下面传过来的int值定义为value数组的长度
AbstractStringBuilder(int capacity) {value = new char[capacity];
}
根据append方法查看追加的流程
这里是将字符串"str"添加到builder中
builder.append("str");
通过append方法,我们进入到了StringBuilder的源码界面
public StringBuilder append(String str) {super.append(str);return this;
}
可以看到追加操作同样是调用的超类提供的追加方法
super.append(str);
跟着继续深入,我们就看见了定义在超类中的追加方法
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;
}
首先,进入该方法后,会先判断传入的字符串是否为空,如果为空的话,会调用appendNull方法
return appendNull();
先看一下该方法
在这里会先将数组的长度值给到c中,再调用ensureCapacityInternal方法来对数组进行扩容
之后将扩完容的数组的地址交给局部的char[]数组中,再在后面接上null4个字符,再将新的数组长度返给count
也就是说如果在调用append方法时传入的是一个null值时,会在整个数组最后面拼上一个null。
private AbstractStringBuilder appendNull() {int c = count; //将当前StringBuilder对象的字符长度赋给censureCapacityInternal(c + 4);final char[] value = this.value;value[c++] = 'n';value[c++] = 'u';value[c++] = 'l';value[c++] = 'l';count = c;return this;
}
接下来继续跟着正常执行走
int len = str.length();//这里是获取传入的字符串的长度
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
这里同样调用了对数组进行扩容的方法ensureCapacityInternal
private void ensureCapacityInternal(int minimumCapacity) {//这里的形参名为最小容积// overflow-conscious code count 现有长度 len 计划添加的长度if (minimumCapacity - value.length > 0)expandCapacity(minimumCapacity);
}
会在这个方法进行一次判断,如果现在我们所需要的最小容积是小于value数组的现有长度的话,就证明数组长度是够用的,就不用进行扩容操作,返回去进行后续操作即可。
但如果最小容积大于了现有数组长度的话,就证明数组长度是不够用的,放不下新添加的字符串,就需要进行扩容操作,就会调用expandcapacity方法,并将我们现在所需要的最小容积传进去
void expandCapacity(int minimumCapacity) {int newCapacity = value.length * 2 + 2;if (newCapacity - minimumCapacity < 0)newCapacity = minimumCapacity;if (newCapacity < 0) {if (minimumCapacity < 0) // overflowthrow new OutOfMemoryError();newCapacity = Integer.MAX_VALUE;}value = Arrays.copyOf(value, newCapacity);
}
就方法的理论而言,你既然进来这里了,那就代表这数组不够用了,所以直接对现有的数组长度进行增加,增加的长度是原长度的一倍加上2
int newCapacity = value.length * 2 + 2;
然后在此基础上对新增后的长度和我们所需要的最小容积进行比较,如果扩容后的长度是够用了的那就直接进行下一步操作,如果扩容后的长度还是不够用,那就直接将我们所需要的最小容积定义为新长度
if (newCapacity - minimumCapacity < 0)newCapacity = minimumCapacity;
在之后会对数据进行一个安全性的验证,因为int类型的值在计算中是可能出现溢出现象的,所以就要先确定一下我们的新数组长度是否溢出了,如果溢出了就强制将值改为int类型的最大值。并且在这次验证里面也要验证一下我们所需的最小容积是否出现了溢出现象,因为如果需求的最小容积如果出现了溢出,而我们的长度只能是int的最大值。也就代表着会有数据会丢失,那这就不该是我们程序背锅,就直接抛出一个内存溢出错误,让程序员去解决。
if (newCapacity < 0) {if (minimumCapacity < 0) // overflowthrow new OutOfMemoryError();newCapacity = Integer.MAX_VALUE;
}
在上面的一系列验证的完成并确保无误后,数组就会开始扩容操作
value = Arrays.copyOf(value, newCapacity);
在完成了扩容后会调用字符串的getChars方法来将字符串添加到字符数组中
str.getChars(0, len, value, count);
getChars方法
getChars(int start, int end, char[] array, int begin);
/*start:复制字符串时字符串的起始位置end: 复制结束的位置array:复制指向的字符数组begin:数组接收的起始位置
*/
所以可以看出,对字符串的复制就是将整个字符串按照count的位置开始填入数组中
最后再将count的值改变,以对应现在数组的长度
count += len;
对StringBuilder的append方法底层详解相关推荐
- HashMap的containsKey方法底层详解
containsKey方法简介 用 containsKey(key) 方法来检查 key 是否存在, 源码分析 /** * 检查是否包含key * 如果key有对应的节点对象,则返回ture,不关心节 ...
- java 获取用户的MAC地址多种方法实例详解
java 获取用户的MAC地址多种方法实例详解 这篇文章主要介绍了JAVA实现获取用户的MAC地址的多种方法实例,需要的朋友可以参考下 java实现获取用户的MAC地址方法: 方法一:将本机地址与局域 ...
- Redis五种基本数据类型底层详解(原理篇)
Redis五种基本数据类型底层详解 详细介绍Redis用到的数据结构 简单动态字符串 SDS和C字符串的区别 总结 链表 字典 哈希表 字典 哈希算法 解决键冲突 rehash(重点) 渐进式reha ...
- jquery方法属性详解
jquery方法属性详解! 1.jquery简介 jquery是什么,作用是什么? jquery用来简化js操作DOM元素 jquery不能用DOM的方法,DOM不能用jquery的方法 各种选择器的 ...
- StringBuilder的append方法原理
关于字符串拼接,我们一般使用+号对String类进行拼接,但实际上这是一种非常不高效的方法,而另一种方法就是使用StringBuilder类的append方法,这是一种非常高效的方式. 今天也是被面试 ...
- golang导入git包_使用go module导入本地包的方法教程详解
go module 是Go1.11版本之后官方推出的版本管理工具,并且从 Go1.13 版本开始, go module 将是Go语言默认的依赖管理工具.到今天 Go1.14 版本推出之后 Go mod ...
- java condition详解_Java使用Condition控制线程通信的方法实例详解
Java使用Condition控制线程通信的方法实例详解 发布于 2020-4-20| 复制链接 摘记: 本文实例讲述了Java使用Condition控制线程通信的方法.分享给大家供大家参考,具体如下 ...
- python怎么画条形图-python绘制条形图方法代码详解
1.首先要绘制一个简单的条形图 import numpy as np import matplotlib.pyplot as plt from matplotlib import mlab from ...
- python装饰器函数-Python函数装饰器常见使用方法实例详解
本文实例讲述了Python函数装饰器常见使用方法.分享给大家供大家参考,具体如下: 一.装饰器 首先,我们要了解到什么是开放封闭式原则? 软件一旦上线后,对修改源代码是封闭的,对功能的扩张是开放的,所 ...
最新文章
- ChIP-seq基本分析流程
- View工作原理(四)view的layout过程
- python数字处理技巧(1): 精度舍入、精确运算、格式化、进制数、大数打包解包、复数、NaN、分数
- 程序员们怎么过端午?你属于哪一款?
- ofo 悄然搬离中关村;董明珠称向雷军学互联网营销;Chrome 77 发布 | 极客头条...
- 蓝桥杯java 大纲,2019 第十届蓝桥杯Java省赛B组个人总结
- MyDAL - is null is not null 条件 使用
- Docker下Cannot connect to the Docker daemon. Is the docker daemon running on this host错误解决方案
- 微信群发机器人源代码
- Python代码转EXE程序
- 高中数学压轴解答题:函数零点
- python的拼音_Python之拼音拆分
- IE 提示 当前安全设置不允许下载该文件
- Python词云_自定义图片做背景
- android百度输入法切换,百度输入法输入模式怎么切换 快速一键切换输入法模式方法教程...
- 马踏棋盘问题的程序c语言,C语言马踏棋盘
- 基于java的写字板的设计
- 解决mac pro 装 win10以后 蓝牙 卡顿的问题
- MATLAB 詹姆斯韦伯天文望远镜轨迹 粗略效果仿真 (二)
- 什么是拓扑(Topology) - 3D 角色 建模过程中的 中的术语:拓扑