StringBuffer 和 StringBuilder

介绍

大多数情况下, StringBuffer 的速度要比 String 快; StringBuilder 要比StringBuffer快;StringBuffer 和 StringBuilder 都是 AbstractStringBuilder 的子类,区别在于StringBuffer 的方法大部分都有 synchronized 修饰。

源码解析

AbstractStringBuilder

变量及构造方法


/**
* 用来存储字符的数组
* The value is used for character storage.
*/
char[] value; /**
* 字符个数
* The count is the number of characters used.
*/
int count; /**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
} /**
* 在构造方法中指定字符数组的长度
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}

扩容

public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
} private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
} private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
} private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}

扩容的方法最终由 newCapacity() 实现的,首先将容量左移一位(即扩大2倍)同时加2,如果此时任小于指定的容量,那么就将容量设置为 minimumCapacity 。然后判断是否溢出,通过 hugeCapacity 实现,如果溢出了(长度大于 Integer.MAX_VALUE ),则抛错( OutOfMemoryError );否则根据 minCapacityInteger.MAX_VALUE - 8 的大小比较确定数组容量为 max(minCapacity, Integer.MAX_VALUE - 8)。最后将 value 值进行拷贝,这一步显然是最耗时的操作。

append() 方法

public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}

append() 是最常用的方法,它有很多形式的重载。上面是最常用的一种,用于追加字符串。如果 strnull ,则直接调用

appendNull() 方法。这个方法就是直接追加 'n''u''l''l' 这几个字符,方法如下:


private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}

如果不是null,则首先需要判断数组容量是否足够,不够则需要扩容(扩容则是调用上述分析的扩容方法);

然后调用 StringgetChars() 方法将 str 追加到 value 末尾;

最后返回对象本身,所以 append() 可以连续调用(就是一种类似于链式编程)。

思考

  • 为什么每次扩容是扩容为原来的两倍?

    个人觉得是为了避免经常扩容带来的成本消耗。
  • 为什么会加2呢?

    个人也没想出什么好的解释,觉得可能是因为 Java 开发者认为我们在 append 数据的时候,中间经常会加一个分隔符,恰好这个分隔符在 Java 中正好占用两个字节。也不知道分析的对不对,有其他意见的大佬们可以在 issue

    中进行讨论。

StringBuilder 与 StringBuffer 方法对比

通过查看源码分析发现两者都继承至 AbstractStringBuilder 。 而 StringBuffer 之所以是线程安全的,是因为重写 AbstractStringBuilder 的方法的时候在前面加上了 synchronzied 修饰这些方法;而 StringBuilder 重写的时候只是直接调用父类的方法,没有做其他的操作。

其实通过阅读源码发现 StringBuilderStringBuffer 之间的关系,类似于 HashMapHashTable 之间的关系。

StringBuffer 和 StringBuilder 总结的更多相关文章

  1. 测试一下StringBuffer和StringBuilder及字面常量拼接三种字符串的效率

    之前一篇里写过字符串常用类的三种方式<java中的字符串相关知识整理>,只不过这个只是分析并不知道他们之间会有多大的区别,或者所谓的StringBuffer能提升多少拼接效率呢?为此写个简 ...

  2. String、StringBuffer与StringBuilder之间区别

    关于这三个类在字符串处理中的位置不言而喻,那么他们到底有什么优缺点,到底什么时候该用谁呢?下面我们从以下几点说明一下 1.三者在执行速度方面的比较:StringBuilder >  String ...

  3. 关于StringBuffer和StringBuilder

    StringBuffer 字符串特点:字符串是常量:它们的值在创建之后不能更改. 字符串的内容一旦发生了变化,那么马上会创建一个新 的对象. 注意: 字符串的内容不适宜频繁修改,因为一旦修改马上就会创 ...

  4. 谈谈StringBuffer和StringBuilder

    (1) 速度 在执行速度方面的比较:StringBuilder > StringBuffer > String ①String 是不可变的对象(String类源码中存放字符的数组被声明为f ...

  5. (转)String、StringBuffer与StringBuilder之间区别

    原文地址: http://www.cnblogs.com/A_ming/archive/2010/04/13/1711395.html 关于这三个类在字符串处理中的位置不言而喻,那么他们到底有什么优缺 ...

  6. Java中String、StringBuffer、StringBuilder区别与理解

    一.先比较String.StringBuffer.StringBuilder变量的HashCode值 使用System.out.println(obj.hashcode())输出的时对象的哈希码, 而 ...

  7. String、Stringbuffer、StringBuilder的区别(转载)

    最近学习到StringBuffer,心中有好些疑问,搜索了一些关于String,StringBuffer,StringBuilder的东西,现在整理一下. 关于这三个类在字符串处理中的位置不言而喻,那 ...

  8. String、StringBuffer和StringBuilder的深入解析

    今天闲来无事,整理了下平时记录在印象笔记里的java开发知识点,整理到String,StringBuffer以及StringBuilder的区别时突然又产生了新的疑惑,这些区别是怎么产生的?温故为何能 ...

  9. String、StringBuffer、StringBuilder的区别

    在日常开发过程中String字符串估计是被用到最多的变量了,最近看了一些String.StringBuffer和StringBuilder的东西,三者都可以对字符串进行操作,他们究竟有什么区别,以及适 ...

  10. Java String,StringBuffer和StringBuilder的区别

    [可变与不可变] String是字符串常量,不可变. StringBuffer和StringBuilder是字符串变量,可变. [执行速度方面] StringBuilder > StringBu ...

随机推荐

  1. 【leetcode】1137. N-th Tribonacci Number

    题目如下: The Tribonacci sequence Tn is defined as follows: T0 = 0, T1 = 1, T2 = 1, and Tn+3 = Tn + Tn+1 ...

  2. LeetCode--094--二叉树的中序遍历(python)

    递归 # Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # ...

  3. 【转载】MIMO技术杂谈(一):鱼与熊掌能否兼得?--浅谈分集与复用的权衡

    原文链接(向作者致敬):http://www.txrjy.com/thread-667901-1-1.html   无线通信世界在过去的几十年中的发展简直是爆发式的,MIMO(多发多收)技术的出现更是 ...

  4. 6364. 【NOIP2019模拟2019.9.20】养马

    题目描述 题解 一种显然的水法:max(0,-(点权-边权之和*2)) 这样会挂是因为在中途体力值可能会更小,所以考虑求走完每棵子树所需的至少体力值 考虑从子树往上推求出当前点的答案 设每棵子树从根往 ...

  5. opencv入门教程三

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/20537737 作者:毛星云(浅墨)  ...

  6. idea创建项目和依赖

    创建项目和依赖 项目搭建完成后打开web.xml可看到如图使用的是servlet2.3,但版本太老,servlet2.3 jsp  的el表达式不工作,所以我们需要切换新版本. 切换新版本方法:打开t ...

  7. [CSP-S模拟测试]:回家(塔尖)

    题目传送门(内部题7) 输入格式 第一行一个整数$T$,表示共$T$组数据.对于每组数据,第一行两个数$n,m$表示有$n$个建筑物,$m$条道路.接下来$m$行,每行两个整数$u,v$,表示第$u$ ...

  8. IntelliJ IDEA 开发工具的一些设置

    IntelliJ IDEA 开发工具的一些设置 参考资料 IntelliJ IDEA 的学习,离不开网络上技术热爱者们的分享,在此向他们表示感谢. 成吨提高开发效率:https://github.co ...

  9. twitter api的使用

    1.用手机号注册推特账号 https://twitter.com/ 2.进入网站 https://apps.twitter.com/ 创建第一个app,填入基本信息 name写完会检测是否已经存在像我 ...

  10. foreach(增强for循环)和for的区别

    https://www.cnblogs.com/XiaojianGo/p/7471860.html 首先说一下foreach有的也叫增强for循环,foreach其实是for循环的一个特殊简化版. 再 ...