StringBufferStringBuilder,它们的底层char数组value默认的初始化容量是16,扩容只需要修改底层的char数组,两者的扩容最终都会调用到AbstractStringBuilder类相同的方法:

直入正题,扩容的步骤:

  1. 新的字符串的长度超过了底层原char数组value的大小,才需要进行扩容
  2. 先尝试默认扩容,将新容量变成 (value.length << 1) + 2 ,也就是两倍的原数组长度再加二
  3. 若默认扩充后的值还是小于至少容量的值,直接扩充到当前需要的至少容量大小;
  4. 经过前两步骤确定的新数组大小,若大于Interger.MAX_VALUE,则报异常,若小于等于0,则新数组大小改为Interger.MAX_VALUE-8
  5. 确定了新数组的值后,通过Arrays.copy(value,newCapactity)。最终给value数组完成扩容,新数组大小为newCapactity

这样扩容的目的,宏观上是尽可能地减少扩容次数,提高效率。

肯定有同学会问,默认扩容为什么是两倍原数组长度 + 2 ,因为源码并无说明这样设计的原因,所以根据我找到的资料结合我的推测,可能的原因有这些:

  • 考虑到在自定义初始化StringBuffer长度不大时(例如1),+2 可以很大地提升扩容的效率,减少扩容的次数
  • 在旧版本的JDK扩容语句是 (value.length + 1) * 2 先加一再乘2,推测原意思是扩容的话至少增添一个空间再乘2,兼顾到扩容的次数和要减少扩容过大浪费的空间
  • newCapacity(int)的传入参数有可能是0,那么在参数是0的情况下,0<<1运算结果也是0,如果没+2,那么在创建数组的时候会创建出MAX_ARRAY_SIZE大小,所以作为设计的安全性考虑,选择了+2。(本人认为除了反射调用newCapacity,其他情况应该不会出现newCapacity(int)的传入0为参数)
  • append(str)后需补充分隔符所预留的位置,为了减少扩容次数 (个人感觉这点不太靠谱)

下面是在JDK1.8中AbstractStringBuilder有关计算扩容的方法:

//AbstractStringBuilder.java 

private void ensureCapacityInternal(int minimumCapacity) {
//若所需长度大于已有长度,才继续进行扩容
if (minimumCapacity - value.length > 0) {
//通过Arrays.copyOf(),将旧value数组内容先复制到newCapacity大小的数组,再赋值给新value
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
// 默认扩容:newCapacity = 两倍的原长度 + 2
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {//默认扩容后还是小于所需长度
newCapacity = minCapacity;//直接补充至所需长度
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)//newCapacity>MAX_ARRAY_SIZE 或者≤0会调用
: newCapacity;
} MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { //大小超出Integer范围爆异常
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE) //返回minCapacity与MAX_ARRAY_SIZE最大值
? minCapacity : MAX_ARRAY_SIZE;
}

希望对你有所帮助~

最新文章

  1. HTML5音乐播放器(最新升级改造加强版)
  2. CSS 笔记一(Selectors/ Backgrounds/ Borders/ Margins/ Padding/ Height and Width)
  3. Unity-Animator深入系列---API详解
  4. 深入浅出OOP(一): 多态和继承(早期绑定/编译时多态)
  5. 使用命令行工具将Android应用转换成BlackBerry PlayBook应用
  6. poj 3740 Easy Finding 二进制压缩枚举dfs 与 DLX模板详细解析
  7. JavaWeb项目开发案例精粹-第2章投票系统-006view层
  8. WinServer 之 发布WebService后调用出现&quot; The test form is only available for requests from the local machine. &quot;
  9. TWinControl的刷新过程(5个非虚函数,4个覆盖函数,1个消息函数,默认没有双缓冲,注意区分是TCustomControl还是Windows原生封装控件,执行流程不一样)
  10. Maven工程webinfo下面的JSP页面无法加载.js、.css文件的解决方案
  11. 工作小结(关于webpack)
  12. .NET Core GC 的设计
  13. JS-NaN的数据类型
  14. [date] 时间问题: 更新时间距离现在3个月
  15. npm5踩过的坑!
  16. ubuntu14.04, Cloudera Manager 5.11.1, cdh5.11.1 postgresql离线部署
  17. [Oracle]TM lock (DML enqueue) 的相容性
  18. day02 运算符和编码
  19. C# 数组 二维数组
  20. Python学习(004)-字典{}

热门文章

  1. KMP入门
  2. centos7-修改默认python为3
  3. 使用Rancher在K8S上部署高性能PHP应用程序
  4. Django之模型的_meta属性
  5. Azure Web App (二)使用部署槽切换部署环境
  6. three.js 曲线
  7. 微信小程序 + wepy快速开发
  8. 蒲公英 &#183; JELLY技术周刊 Vol.14: Vue 3 新特性详解
  9. Spring Bean的生命周期 ---附详细流程图及测试代码
  10. 不藏了,摊牌了,一张知识图谱整理完整Java并发体系,就问全不全