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. mysql Unknown error 1146

    错误提示:Couldn't acquire next trigger: Unknown error 1146 spring +quartz 实现任务调度,由于quartz 默认读取表名为大写,新建数据 ...

  2. day59 django初识

    目录 一.借助wsgiref模块实现简易版web框架 二.动静态页面 三.python三大主流web框架 四.启动一个django项目 1 启动前的注意事项 1.1 计算机的问题 1.2 django ...

  3. mysql解压缩版安装和卸载

    所有的cmd命令都是在管理员模式下输入 官方下载网址:https://dev.mysql.com/downloads/mysql/ 安装mysql mysqld install //安装mysql:卸 ...

  4. Scala 基础(五):Scala变量 (二) 数据类型

    1 scala数据类型介绍 Scala 与 Java有着相同的数据类型,在Scala中数据类型都是对象,也就是说scala没有java中的原生类型 Scala数据类型分为两大类 AnyVal(值类型) ...

  5. shell专题(三):Shell脚本入门

    1.脚本格式 脚本以#!/bin/bash开头(指定解析器) 2.第一个Shell脚本:helloworld (1)需求:创建一个Shell脚本,输出helloworld (2)案例实操: [atgu ...

  6. Django之 url组件

    本节内容 路由系统 models模型 admin views视图 template模板 路由系统 我们已知,用户从浏览器发出的请求会首先打到django url的路由分发系统这里,然后再到views视 ...

  7. bzoj2295【POJ Challenge】我爱你啊*

    bzoj2295[POJ Challenge]我爱你啊 题意: 求一个字符串中有多少个"luvletter"(不包括引号).字符串长度≤100000. 题解: 连kmp都不用…… ...

  8. oracle数据库备份还原命令

    oracle数据库备份命令exp 用户名/密码@orcl file=d:\xxxxxx.dmp owner=用户名 oracle数据库还原命令sqlplus conn / as sysdba drop ...

  9. django admin后台管理功能的学习

    1.简要说明 用过Django框架的童鞋肯定都知道,在创建完Django项目后,每个app下,都会有一个urls.py文件,里边会有如下几行: from django.contrib import a ...

  10. markdownpad2初使用

      本来是想在csdn上写blog的,到那时不知道为什么,那个写blog的界面总是崩溃,写了半天的东西和公式也都没有了,很气愤,所以就准备下载一个本地的markdown编辑器,下载课两款一款是mark ...