用大白话的方式讲明白Java的StringBuilder、StringBuffer的扩容机制
StringBuffer和StringBuilder,它们的底层char数组value默认的初始化容量是16,扩容只需要修改底层的char数组,两者的扩容最终都会调用到AbstractStringBuilder类相同的方法:
直入正题,扩容的步骤:
- 新的字符串的长度超过了底层原char数组value的大小,才需要进行扩容
- 先尝试默认扩容,将新容量变成 (value.length << 1) + 2 ,也就是两倍的原数组长度再加二
- 若默认扩充后的值还是小于至少容量的值,直接扩充到当前需要的至少容量大小;
- 经过前两步骤确定的新数组大小,若大于Interger.MAX_VALUE,则报异常,若小于等于0,则新数组大小改为Interger.MAX_VALUE-8
- 确定了新数组的值后,通过
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的扩容机制的更多相关文章
- 浅谈JAVA中HashMap、ArrayList、StringBuilder等的扩容机制
JAVA中的部分需要扩容的内容总结如下:第一部分: HashMap<String, String> hmap=new HashMap<>(); HashSet<Strin ...
- 面试题: Java中各个集合类的扩容机制
个人博客网:https://wushaopei.github.io/ (你想要这里多有) Java 中提供了很多的集合类,包括,collection的子接口list.set,以及map等.由于它 ...
- 【转载】关于Java String, StringBuilder, StringBuffer, Hashtable, HashMap的面试题
REF: http://blog.csdn.net/fightforyourdream/article/details/15333405 题目是一道简单的小程序,像下面这样:[java] view p ...
- 用大白话聊聊JavaSE -- 如何理解Java Bean(一)
首先,在开始本章之前,先说一个总的概念:所谓的Java Bean,就是一个java类,编译后成为了一个后缀名是 .class的文件.这就是Java Bean,很多初学者,包括当年的我自己,总是被这些专 ...
- Java - String, Stringbuilder, StringBuffer比较
http://www.cnblogs.com/zuoxiaolong/p/lang1.html
- Java String StringBuilder StringBuffer
String是字符串常量 StringBuilder和StringBuffer都是字符串变量 速度方面:StringBuilder > StringBuffer > String 每当用S ...
- 用大白话讲Java动态代理的原理
动态代理是什么 首先说下代理模式,代理模式是常见的一种java设计模式,特征是代理类与委托类实现了同样的接口,代理类主要负责为委托类预处理.过滤.转发,以及事后处理等.代理类与委托类之间通常会存在关联 ...
- Java并发编程:Concurrent锁机制解析
Java并发编程:Concurrent锁机制解析 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: # ...
- 用大白话讲大数据HBase,老刘真的很用心(1)
老刘今天复习HBase知识发现很多资料都没有把概念说清楚,有很多专业名词一笔带过没有解释.比如这个框架高性能.高可用,那什么是高性能高可用?怎么实现的高性能高可用?没说! 如果面试官听了你说的,会有什 ...
随机推荐
- mysql两种重要的引擎
其中MyISAM:不支持事物,表锁 .frm : 表结构定义文件 .MYD: 表数据 .MYI:索引文件 InnoDB:支持事物,行锁 .frm : 表结构定义文件 .ibd:表空间(数据和索引)
- 【Nginx】如何获取客户端真实IP、域名、协议、端口?看这一篇就够了!
写在前面 Nginx最为最受欢迎的反向代理和负载均衡服务器,被广泛的应用于互联网项目中.这不仅仅是因为Nginx本身比较轻量,更多的是得益于Nginx的高性能特性,以及支持插件化开发,为此,很多开发者 ...
- 攻防世界FlatScience
访问robots.txt发现 admin.php和login.php 在admin.php和login.php分别尝试注入 发现login.php页面存在注入,并且根据报错得知数据库类型为sqlite ...
- JVM 专题四:类加载子系统(二)双亲委派机制
2. 双亲委派机制 2.1 双亲委派机制工作原理 2.1.1 原理 Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存,生成class对象 ...
- Python 图像处理 OpenCV (14):图像金字塔
前文传送门: 「Python 图像处理 OpenCV (1):入门」 「Python 图像处理 OpenCV (2):像素处理与 Numpy 操作以及 Matplotlib 显示图像」 「Python ...
- MnasNet:经典轻量级神经网络搜索方法 | CVPR 2019
论文提出了移动端的神经网络架构搜索方法,该方法主要有两个思路,首先使用多目标优化方法将模型在实际设备上的耗时融入搜索中,然后使用分解的层次搜索空间,来让网络保持层多样性的同时,搜索空间依然很简洁,能够 ...
- 重装win7时遇到点小问题
最近装系统的时候有个头疼的事,事情的起因是这样的,我在工作的时候用的win7,破解的时候各种工具都破解不了,说是有未分配的盘符.并且,当时装的是没更新的win7,工作上要用到ie11只能在w ...
- 解决redis秒杀超卖的问题
我们再使用redis做秒杀程序的时候,解决超卖问题,是重中之重.以下是一个思路. 用上述思路去做的话,我们再用户点击秒杀的时候,只需要检测,kucun_count中是否能pop出数据,如果能pop出来 ...
- Java面试题汇总(持续更新)
1. ==和equals的区别 答: 基础数据类型比较:只能使用==,比较值是否相等 引用数据类型比较: 没有重写equals方法:==和equals没有区别,比较的都是引用是否指向了同一块内存 重写 ...
- git分支间切换注意点和bug分支的处理
目录 备注: 知识点 记一次分支合并问题状况 从分支点开始,不同分支修改工作区的内容(不添加到暂存区和提交),切换分支,工作区的内容是一样的. 必须在提交或者暂存当前暂存区的状态后,再切换或合并分支 ...