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;
}

希望对你有所帮助~

用大白话的方式讲明白Java的StringBuilder、StringBuffer的扩容机制的更多相关文章

  1. 浅谈JAVA中HashMap、ArrayList、StringBuilder等的扩容机制

    JAVA中的部分需要扩容的内容总结如下:第一部分: HashMap<String, String> hmap=new HashMap<>(); HashSet<Strin ...

  2. 面试题: Java中各个集合类的扩容机制

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) Java 中提供了很多的集合类,包括,collection的子接口list.set,以及map等.由于它 ...

  3. 【转载】关于Java String, StringBuilder, StringBuffer, Hashtable, HashMap的面试题

    REF: http://blog.csdn.net/fightforyourdream/article/details/15333405 题目是一道简单的小程序,像下面这样:[java] view p ...

  4. 用大白话聊聊JavaSE -- 如何理解Java Bean(一)

    首先,在开始本章之前,先说一个总的概念:所谓的Java Bean,就是一个java类,编译后成为了一个后缀名是 .class的文件.这就是Java Bean,很多初学者,包括当年的我自己,总是被这些专 ...

  5. Java - String, Stringbuilder, StringBuffer比较

    http://www.cnblogs.com/zuoxiaolong/p/lang1.html

  6. Java String StringBuilder StringBuffer

    String是字符串常量 StringBuilder和StringBuffer都是字符串变量 速度方面:StringBuilder > StringBuffer > String 每当用S ...

  7. 用大白话讲Java动态代理的原理

    动态代理是什么 首先说下代理模式,代理模式是常见的一种java设计模式,特征是代理类与委托类实现了同样的接口,代理类主要负责为委托类预处理.过滤.转发,以及事后处理等.代理类与委托类之间通常会存在关联 ...

  8. Java并发编程:Concurrent锁机制解析

    Java并发编程:Concurrent锁机制解析 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: # ...

  9. 用大白话讲大数据HBase,老刘真的很用心(1)

    老刘今天复习HBase知识发现很多资料都没有把概念说清楚,有很多专业名词一笔带过没有解释.比如这个框架高性能.高可用,那什么是高性能高可用?怎么实现的高性能高可用?没说! 如果面试官听了你说的,会有什 ...

随机推荐

  1. Docker镜像-删除镜像

    因为尝试使用新的镜像,对原来的镜像进行删除,报错如下: 意思就是在删除镜像之前,要先删除对应的docker.因为该image被对应的container引用,所以image删除失败. 显示所有状态的容器 ...

  2. 【Windows10】如何使用Segoe MDL2 Assets图标

    众所周知,在Windows 10中,微软引入了汉堡菜单,方便Android和ios的开发者移植程序,而不需要单独为Windows设计一套UI.但有人可能发现在symbol icon里根本找不到所谓的汉 ...

  3. unity spine 对翻转和大小的控制

    spine-unity怎么决定我的Spine模型的大小? Spine使用 1像素:1单位.意思是,如果你只是包含图像在你的骨架中,并且没有任何旋转和缩放,在Spine中该图像的1个像素就对应1个单位高 ...

  4. Django---drf第一天---作业

    1 图书的5个接口写完(使用序列化组件) urls.py from django.contrib import admin from django.urls import path, re_path ...

  5. 师兄大厂面试遇到这条 SQL 数据分析题,差点含泪而归!

    写在前面:我是「云祁」,一枚热爱技术.会写诗的大数据开发猿.昵称来源于王安石诗中一句 [ 云之祁祁,或雨于渊 ] ,甚是喜欢. 写博客一方面是对自己学习的一点点总结及记录,另一方面则是希望能够帮助更多 ...

  6. day58 前端收尾

    目录 一.jQuery结束 1 阻止后续事件执行 2 阻止事件冒泡 3 事件委托 4 页面加载 5 动画效果 6 补充知识点 二.前端框架Bootstrap 1 布局容器 2 栅格系统 3 栅格参数 ...

  7. day29 作业

    1.引入属性访问控制+property 2.引入继承与派生的概念来减少代码冗余 注意:要满足什么"是"什么的关系,不满足"是"的关系不要去继承 import u ...

  8. Python之爬虫(二十) Scrapy爬取所有知乎用户信息(上)

    爬取的思路 首先我们应该找到一个账号,这个账号被关注的人和关注的人都相对比较多的,就是下图中金字塔顶端的人,然后通过爬取这个账号的信息后,再爬取他关注的人和被关注的人的账号信息,然后爬取被关注人的账号 ...

  9. 安卓移动端line-height垂直居中出现偏移的解决方法

    目前移动端在项目使用的rem,安卓手机上line-height属性,让它的值等于height,结果发现是不居中的. 出现此问题的原因是Android在排版计算的时候参考了primyfont字体的相关属 ...

  10. 手写SpringBoot自动配置及自定义注解搭配Aop,实现升级版@Value()功能

    背景 项目中为了统一管理项目的配置,比如接口地址,操作类别等信息,需要一个统一的配置管理中心,类似nacos. 我根据项目的需求写了一套分布式配置中心,测试无误后,改为单体应用并耦合到项目中.项目中使 ...