从源码角度简单看StringBuilder和StringBuffer的异同(全面解析)

概述

StringBuilder和StringBuffer是两个容易混淆的概念,本文从源码入手,简单看二者的异同。

容易知道的是,这两者有一个是线程安全的,而且线程安全的那个效率低。

java doc里面的说明

java doc是写源码的人写的注释,先看java doc。

StringBuilder

A mutable sequence of characters. This class provides an API compatible with StringBuffer, but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.

The principal operations on a StringBuilder are the append and insert methods, which are overloaded so as to accept data of any type. Each effectively converts a given datum to a string and then appends or inserts the characters of that string to the string builder. The append method always adds these characters at the end of the builder; the insert method adds the characters at a specified point.

For example, if z refers to a string builder object whose current contents are "start", then the method call z.append("le") would cause the string builder to contain "startle", whereas z.insert(4, "le") would alter the string builder to contain "starlet".

In general, if sb refers to an instance of a StringBuilder, then sb.append(x) has the same effect as sb.insert(sb.length(), x).

Every string builder has a capacity. As long as the length of the character sequence contained in the string builder does not exceed the capacity, it is not necessary to allocate a new internal buffer. If the internal buffer overflows, it is automatically made larger.

Instances of StringBuilder are not safe for use by multiple threads. If such synchronization is required then it is recommended that java.lang.StringBuffer be used.

Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.

Since:
1.5
Author:
Michael McCloskey
See Also:
java.lang.StringBuffer
java.lang.String

StringBuffer

A thread-safe, mutable sequence of characters. A string buffer is like a String, but can be modified. At any point in time it contains some particular sequence of characters, but the length and content of the sequence can be changed through certain method calls.

String buffers are safe for use by multiple threads. The methods are synchronized where necessary so that all the operations on any particular instance behave as if they occur in some serial order that is consistent with the order of the method calls made by each of the individual threads involved.

The principal operations on a StringBuffer are the append and insert methods, which are overloaded so as to accept data of any type. Each effectively converts a given datum to a string and then appends or inserts the characters of that string to the string buffer. The append method always adds these characters at the end of the buffer; the insert method adds the characters at a specified point.

For example, if z refers to a string buffer object whose current contents are "start", then the method call z.append("le") would cause the string buffer to contain "startle", whereas z.insert(4, "le") would alter the string buffer to contain "starlet".

In general, if sb refers to an instance of a StringBuffer, then sb.append(x) has the same effect as sb.insert(sb.length(),

Whenever an operation occurs involving a source sequence (such as appending or inserting from a source sequence), this class synchronizes only on the string buffer performing the operation, not on the source. Note that while StringBuffer is designed to be safe to use concurrently from multiple threads, if the constructor or the append or insert operation is passed a source sequence that is shared across threads, the calling code must ensure that the operation has a consistent and unchanging view of the source sequence for the duration of the operation. This could be satisfied by the caller holding a lock during the operation's call, by using an immutable source sequence, or by not sharing the source sequence across threads.

Every string buffer has a capacity. As long as the length of the character sequence contained in the string buffer does not exceed the capacity, it is not necessary to allocate a new internal buffer array. If the internal buffer overflows, it is automatically made larger.

Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.

As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.

Since:
JDK1.0
Author:
Arthur van Hoff
See Also:
java.lang.StringBuilder
java.lang.String

javadoc小结

从上面可以看出:

StringBuffer和StringBuilder都可以认为是可变的String。

StringBuffer是线程安全的,先出现,在JDK1.0的时候就有了。

StringBuilder是非线程安全的,后出现,在JDK1.5才有。

二者的接口完全一样,StringBuilder更快。

其实,正常的用,知道这几点就好了,不过还是想看看源码里面怎么实现的。

源码

如何实现线程安全

看源码可以知道,这二者都继承了一个抽象类AbstractStringBuilder

public final class StringBuffer
 extends AbstractStringBuilder
 implements java.io.Serializable, CharSequence

public final class StringBuilder
 extends AbstractStringBuilder
 implements java.io.Serializable, CharSequence 

代码量也不是很大,StringBuilder440行代码,StringBuffer718行代码,最多的是AbstractStringBuilder,一共1440行代码。

看代码从几个角度看,一是一些关键的内部结构是怎么样的,二是我们常用的函数是怎么实现的。因为String是不可变的,是放在常量池里面的。猜测StringBuilder和StringBuffer应该是用char数组实现的。

/**
 * The value is used for character storage.
 */
 char[] value;

 /**
 * The count is the number of characters used.
 */
 int count;

可以看出,用value存数据,用一个count表示长度。

看几个常见方法的不同实现。

StringBuffer

 @Override
 public synchronized StringBuffer append(String str) {
 toStringCache = null;
 super.append(str);
 return this;
 }

 /**
 * @throws StringIndexOutOfBoundsException {@inheritDoc}
 */
 @Override
 public synchronized StringBuffer insert(int offset, String str) {
 toStringCache = null;
 super.insert(offset, str);
 return this;
 }

 @Override
 public synchronized String toString() {
 if (toStringCache == null) {
  toStringCache = Arrays.copyOfRange(value, 0, count);
 }
 return new String(toStringCache, true);
 }

StringBuilder

@Override
 public StringBuilder append(String str) {
 super.append(str);
 return this;
 }

 /**
 * @throws StringIndexOutOfBoundsException {@inheritDoc}
 */
 @Override
 public StringBuilder insert(int offset, String str) {
 super.insert(offset, str);
 return this;
 }

 @Override
 public String toString() {
 // Create a copy, don't share the array
 return new String(value, 0, count);
 }

由代码可知,大部分情况想,StrinbBuffer只是增加了一个synchronized关键字来保证线程安全。但toString方法不同,这个后面再说。

初始化大小和如何增长

既然实际上是一个数组,那么数组开始的大小和增长的方法就很重要,我们通过代码看一下。

/**
 * Constructs a string buffer with no characters in it and an
 * initial capacity of 16 characters.
 */
 public StringBuffer() {
 super(16);
 }

 /**
 * Constructs a string builder with no characters in it and an
 * initial capacity of 16 characters.
 */
 public StringBuilder() {
 super(16);
 }

可以看到,这两个默认构造函数都说明默认的数组大小是16。

为什么是16呢?我没想明白。

接下来关心如何增长的?我们看看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;
 }

 /**
 * This method has the same contract as ensureCapacity, but is
 * never synchronized.
 */
 private void ensureCapacityInternal(int minimumCapacity) {
 // overflow-conscious code
 if (minimumCapacity - value.length > 0)
  expandCapacity(minimumCapacity);
 }

 /**
 * This implements the expansion semantics of ensureCapacity with no
 * size check or synchronization.
 */
 void expandCapacity(int minimumCapacity) {
 int newCapacity = value.length * 2 + 2;
 if (newCapacity - minimumCapacity < 0)
  newCapacity = minimumCapacity;
 if (newCapacity < 0) {
  if (minimumCapacity < 0) // overflow
  throw new OutOfMemoryError();
  newCapacity = Integer.MAX_VALUE;
 }
 value = Arrays.copyOf(value, newCapacity);
 }

上面三个方法说明了如何扩容。

把当前的容量*2+2

如果新增加的长度大于这个值,则设为新增加的值

如果溢出,则抛出OutOfMemoryError

StringBuffer中toString的实现

/**
 * A cache of the last value returned by toString. Cleared
 * whenever the StringBuffer is modified.
 */
 private transient char[] toStringCache;

 @Override
 public synchronized StringBuffer append(String str) {
 toStringCache = null;
 super.append(str);
 return this;
 }
 @Override
 public synchronized String toString() {
 if (toStringCache == null) {
  toStringCache = Arrays.copyOfRange(value, 0, count);
 }
 return new String(toStringCache, true);
 }

可以看到,定义了一个数组toStringCache,每次数据有变化,都把这个设置为null。在toString的时候,再重新从当前数据里面拿。

transient关键字是为了避免这个数组被序列化。

小结

其实java本身的源码写的还是比较简单的,学习知识如果能从源码入手,能够更深入的理解很多原理。本文只是简单的列举了一部分源码,简单说明StringBuffer和StringBuilder的异同。有兴趣的朋友可以自己看一下。

以上这篇从源码角度简单看StringBuilder和StringBuffer的异同(全面解析)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

您可能感兴趣的文章:

  • Java之String、StringBuffer、StringBuilder的区别分析
  • 深入解析StringBuffer和StringBuilder的区别
  • Java StringBuilder和StringBuffer源码分析
  • Java中String、StringBuffer、StringBuilder的区别详解
  • Java那点事——StringBuffer与StringBuilder原理与区别
  • Java 中String StringBuilder 与 StringBuffer详解及用法实例
(0)

相关推荐

  • Java 中String StringBuilder 与 StringBuffer详解及用法实例

    在Android/Java开发中,用来处理字符串常用的类有3种: String.StringBuilder.StringBuffer. 它们的异同点: 1) 都是 final 类, 都不允许被继承; 2) String 长度是不可变的, StringBuffer.StringBuilder 长度是可变的; 3) StringBuffer 是线程安全的, StringBuilder 不是线程安全的. String VS StringBuffer String 类型和StringBuffer的主要性

  • Java之String、StringBuffer、StringBuilder的区别分析

    相信大家对 String 和 StringBuffer 的区别也已经很了解了,但是估计还是会有很多同志对这两个类的工作原理有些不清楚的地方,今天我在这里重新把这个概念给大家复习一下,顺便牵出 J2SE 5.0 里面带来的一个新的字符操作的类-- StringBuilder .那么这个 StringBuilder 和 StringBuffer 以及我们最早遇见的 String 类有那些区别呢?在不同的场合下我们应该用哪个呢?我讲讲自己对这几个类的一点看法,也希望大家提出意见,每个人都有错的地方,在

  • Java中String、StringBuffer、StringBuilder的区别详解

    java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可变 String类中使用字符数组保存字符串,如下就是,因为有"final"修饰符,所以可以知道string对象是不可变的. private final char value[]; StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在A

  • Java那点事——StringBuffer与StringBuilder原理与区别

    最近在找工作,考官问我一个简单的题目:"StringBuffer与StringBuilder的区别,它们的应用场景是什么?",下面小编答案分享给大家,方便以后大家学习,以此也做个备录. 其实只要找下Google大神就有答案了:StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全

  • Java StringBuilder和StringBuffer源码分析

    StringBuilder与StringBuffer是两个常用的操作字符串的类.大家都知道,StringBuilder是线程不安全的,而StringBuffer是线程安全的.前者是JDK1.5加入的,后者在JDK1.0就有了.下面分析一下它们的内部实现. 一.继承关系 public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence public

  • 深入解析StringBuffer和StringBuilder的区别

    做项目中经常用到String和StringBuilder,String可以用"+"来对字符串进行拼接,StringBuilder用append进行拼接,一直不明白既然可以用String,问什么还要用StringBuilder.尽管在做数据库查询的时候,习惯性的用了StringBuilder对查询语句进行拼接,但仍然不知道原因.今天看视频的时候,又看到了StringBuffer,感觉用法又差不多,所以特意查了一下这些东西的区别.归纳如下:1.在执行速度方面的比较:StringBuilde

  • 从源码角度简单看StringBuilder和StringBuffer的异同(全面解析)

    概述 StringBuilder和StringBuffer是两个容易混淆的概念,本文从源码入手,简单看二者的异同. 容易知道的是,这两者有一个是线程安全的,而且线程安全的那个效率低. java doc里面的说明 java doc是写源码的人写的注释,先看java doc. StringBuilder A mutable sequence of characters. This class provides an API compatible with StringBuffer, but with

  • Java源码深度分析String与StringBuffer及StringBuilder详解

    目录 StringBuffer和StringBuild的区别 创建StringBuffer() 添加功能 删除功能 替换功能 反转功能 最后总结一下 String的字符串是不可变的,StringBuffer和StringBuilder是可变的 String:是字符常量,适用于少量的字符串操作的情况. StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况 . StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况. StringBuffer和StringBuild

  • Android从源码的角度彻底理解事件分发机制的解析(下)

    记得在前面的文章中,我带大家一起从源码的角度分析了Android中View的事件分发机制,相信阅读过的朋友对View的事件分发已经有比较深刻的理解了. 还未阅读过的朋友,请先参考Android从源码的角度彻底理解事件分发机制的解析. 那么今天我们将继续上次未完成的话题,从源码的角度分析ViewGroup的事件分发. 首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View和子VewGroup,是And

  • 网页源码轻松看

    经常在网上转悠,你一定会发现很多制作精美的网页,那么有没有想过分析它们的源码,将它们的设计思想"借用"过来,给自己的网站也认真装饰一番呢?但是,有些网站的主人却对网页进行了一些限制,让你无法查看源代码,有时候甚至让你无法复制网页上的文字,让人很懊恼.其实,网页源码的查看也有许多技巧可循,只要你掌握了它们,就能够事半功倍地为自己的网页服务,下面就将这些技巧一一介绍给大家. 1.查看带有框架(Frame)的网页源码 如果有的网页中使用了框架(Frame),或者使用了多窗口,那么利用IE菜单

  • 从源码角度看spring mvc的请求处理过程

    在分析spring mvc源码之前,先看一张图: 请求处理的过程: 1.DispatcherServelt作为前端控制器,拦截request对象. 2.DispatcherServlet接收到request对象之后,查询HandlerMapping,得到一个HandlerExecutionChain对象. 3.DispatcherServlet将Handler对象交由HandlerAdapter(适配器模式的典型应用),调用相应的controller方法. 4.Controller方法返回Mod

  • IE view-source 无法查看看源码 JavaScript看网页源码 原创

    第一种:view-source法 view-source是一种协议,早期基本上每个浏览器都支持这个协议.但是不知道什么原因,从IE6 Beta2以后IE就不再支持此协议了.这个方法现在只能用在FireFox浏览器上使用了! 使用方法:在浏览器地址栏中输入 view-source: 回车即可看到网页的源代码了. 第二种:JavaScript法 这种方法似乎也不是通用的,在IE6和Opere浏览器上试验成功,但是在FireFox浏览器上就没成功! 使用方法:在浏览器地址栏中输入 复制代码 代码如下:

  • Android从源码的角度彻底理解事件分发机制的解析(上)

    其实我一直准备写一篇关于Android事件分发机制的文章,从我的第一篇博客开始,就零零散散在好多地方使用到了Android事件分发的知识.也有好多朋友问过我各种问题,比如:onTouch和onTouchEvent有什么区别,又该如何使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图片使用Button而不用ImageView?等等--对于这些问题,我并没有给出非常详细的回答,因为我知道如果想要彻底搞明白这些问题,掌握Android事件分发机

  • String StringBuilder StringBuffer区别以及源码分析

    目录 1. String/StringBuilder/StringBuffer 区别 1.1 String 1.2 StringBuilder 1.3 StringBuffer 2. String/StringBuilder/StringBuffer 源码 2.1 String 源码分析 2.1.1 String 类 2.1.2 String 类的属性 2.1.3 String 类的构造函数 2.1.4 String 类的常用方法 2.2 StringBuilder 源码分析 2.2.1 Str

  • 从源码看angular/material2 中 dialog模块的实现方法

    本文将探讨material2中popup弹窗即其Dialog模块的实现. 使用方法 引入弹窗模块 自己准备作为模板的弹窗内容组件 在需要使用的组件内注入 MatDialog 服务 调用 open 方法创建弹窗,并支持传入配置.数据,以及对关闭事件的订阅 深入源码 进入material2的源码,先从 MatDialog 的代码入手,找到这个 open 方法: open<T>( componentOrTemplateRef: ComponentType<T> | TemplateRef

  • 浅析我对 String、StringBuilder、StringBuffer 的理解

    StringBuilder.StringBuffer 和 String 一样,都是用于存储字符串的. 1.那既然有了 String ,为什么还需要他们两个呢? 原因是 String 是不可变的,它每次的字符串拼接,实际上都会 new 一个新的 String 进行接收. 2.谈谈StringBuilder.StringBuffer他们两个的联系: 我们可以知道 StringBuffer 在 1.0 的时候就发布了,那为什么还需要 StringBuilder 呢?原因是它的大部分方法都上了锁,是线程

随机推荐