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. 自动配置/切换/查看JDK环境变量

    最近老是需要几个版本的JDK切换工作,于是网上收集资料整理,自己写了一个:自动配置/切换/查看JDK环境变量的批处理脚本.顺带3个JDK版本分别是:jdk1.6.0_43,jdk1.7.0_80,jd ...

  2. maven整合eclise

    -Dmaven.multiModuleProjectDirectory=$M2_HOME

  3. 如何在MySQL中使用explain查询SQL的执行计划?

    1.什么是MySQL执行计划 要对执行计划有个比较好的理解,需要先对MySQL的基础结构及查询基本原理有简单的了解. MySQL本身的功能架构分为三个部分,分别是 应用层.逻辑层.物理层,不只是MyS ...

  4. BZOJ 1733: [Usaco2005 feb]Secret Milking Machine 神秘的挤奶机 网络流 + 二分答案

    Description Farmer John is constructing a new milking machine and wishes to keep it secret as long a ...

  5. android读取xml

    /*** 从config.xml中获取版本信息以及应用id* * @param urlPath* @return* @throws Exception*/public List getUpdateIn ...

  6. (8)Linux(客户端)和Windows(服务端)下socket通信实例

    Linux(客户端)和Windows(服务端)下socket通信实例: (1)首先是Windows做客户端,Linux做服务端的程序 Windows   Client端 #include <st ...

  7. Twice Equation

    题目链接:https://nanti.jisuanke.com/t/A1541 题意:给你一个L,要你求一个不小于L的最小数字n,对于一个整数m,满足2*(m+1)*m=n*(n+1). 思路:打表找 ...

  8. three arrays

    three arrays 字典树上贪心 #include<bits/stdc++.h> using namespace std; ][][]; ][]; ]; ]; ][]; ][]; i ...

  9. Solr集群环境搭建

    一.准备工作 首先保证已经安装JDK工具包: [root@localhost opt]# java -version java version "1.8.0_144" Java(T ...

  10. #20175201张驰 实验三 敏捷开发与XP实践

    实验步骤 (一)敏捷开发与XP 一.敏捷开发与XP实践-1 ①实验要求: 敏捷开发与XP实践 http://www.cnblogs.com/rocedu/p/4795776.html, Eclipse ...