用大白话的方式讲明白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 Unknown error 1146
错误提示:Couldn't acquire next trigger: Unknown error 1146 spring +quartz 实现任务调度,由于quartz 默认读取表名为大写,新建数据 ...
- day59 django初识
目录 一.借助wsgiref模块实现简易版web框架 二.动静态页面 三.python三大主流web框架 四.启动一个django项目 1 启动前的注意事项 1.1 计算机的问题 1.2 django ...
- mysql解压缩版安装和卸载
所有的cmd命令都是在管理员模式下输入 官方下载网址:https://dev.mysql.com/downloads/mysql/ 安装mysql mysqld install //安装mysql:卸 ...
- Scala 基础(五):Scala变量 (二) 数据类型
1 scala数据类型介绍 Scala 与 Java有着相同的数据类型,在Scala中数据类型都是对象,也就是说scala没有java中的原生类型 Scala数据类型分为两大类 AnyVal(值类型) ...
- shell专题(三):Shell脚本入门
1.脚本格式 脚本以#!/bin/bash开头(指定解析器) 2.第一个Shell脚本:helloworld (1)需求:创建一个Shell脚本,输出helloworld (2)案例实操: [atgu ...
- Django之 url组件
本节内容 路由系统 models模型 admin views视图 template模板 路由系统 我们已知,用户从浏览器发出的请求会首先打到django url的路由分发系统这里,然后再到views视 ...
- bzoj2295【POJ Challenge】我爱你啊*
bzoj2295[POJ Challenge]我爱你啊 题意: 求一个字符串中有多少个"luvletter"(不包括引号).字符串长度≤100000. 题解: 连kmp都不用…… ...
- oracle数据库备份还原命令
oracle数据库备份命令exp 用户名/密码@orcl file=d:\xxxxxx.dmp owner=用户名 oracle数据库还原命令sqlplus conn / as sysdba drop ...
- django admin后台管理功能的学习
1.简要说明 用过Django框架的童鞋肯定都知道,在创建完Django项目后,每个app下,都会有一个urls.py文件,里边会有如下几行: from django.contrib import a ...
- markdownpad2初使用
本来是想在csdn上写blog的,到那时不知道为什么,那个写blog的界面总是崩溃,写了半天的东西和公式也都没有了,很气愤,所以就准备下载一个本地的markdown编辑器,下载课两款一款是mark ...