关闭

StringBuilder和StringBuffer源码分析

372人阅读 评论(0) 收藏 举报
这篇文章主要针对Java中两个常用的操作字符串的类 StringBuilder和StringBuffer进行源码分析,感兴趣的小伙伴们可以参考一下

StringBuilder与StringBuffer是两个常用的操作字符串的类。大家都知道,StringBuilder是线程不安全的,而StringBuffer是线程安全的。前者是JDK1.5加入的,后者在JDK1.0就有了。下面分析一下它们的内部实现。

一、继承关系

?
publicfinal class StringBuffer
extendsAbstractStringBuilder
implementsjava.io.Serializable, CharSequence
 
publicfinal class StringBuilder
extendsAbstractStringBuilder
implementsjava.io.Serializable, CharSequence

可以看到,两个类的继承关系是一模一样的。Serializable是可以序列化的标志。CharSequence接口包含了charAt()、length() 、subSequence()、toString()这几个方法,String类也实现了这个接口。这里的重点是抽象类AbstractStringBuilder,这个类封装了StringBuilder和StringBuffer大部分操作的实现。

二、AbstractStringBuilder

1、变量及构造方法

?
char[] value;
intcount;
AbstractStringBuilder() {
}
AbstractStringBuilder(intcapacity) {
  value = newchar[capacity];
}

AbstractStringBuilder内部用一个char[]数组保存字符串,可以在构造的时候指定初始容量方法。

2、扩容

?

publicvoid ensureCapacity(intminimumCapacity) {
  if(minimumCapacity > 0)
    ensureCapacityInternal(minimumCapacity);
}
 privatevoid ensureCapacityInternal(intminimumCapacity) {
  // overflow-conscious code
  if(minimumCapacity - value.length > 0)
    expandCapacity(minimumCapacity);
}
voidexpandCapacity(intminimumCapacity) {
  intnewCapacity = value.length * 2+ 2;
  if(newCapacity - minimumCapacity < 0)
    newCapacity = minimumCapacity;
  if(newCapacity < 0) {
    if(minimumCapacity < 0)// overflow
      thrownew OutOfMemoryError();
    newCapacity = Integer.MAX_VALUE;
  }
  value = Arrays.copyOf(value, newCapacity);
}

扩容的方法最终是由expandCapacity()实现的,在这个方法中首先把容量扩大为原来的容量加2,如果此时仍小于指定的容量,那么就把新的容量设为minimumCapacity。然后判断是否溢出,如果溢出了,把容量设为Integer.MAX_VALUE。最后把value值进行拷贝,这显然是耗时操作。

3、append()方法

?
publicAbstractStringBuilder append(String str) {
    if(str == null)
      returnappendNull();
    intlen = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    returnthis;
  }

append()是最常用的方法,它有很多形式的重载。上面是其中一种,用于追加字符串。如果str是null,则会调用appendNull()方法。这个方法其实是追加了'n'、'u'、'l'、'l'这几个字符。如果不是null,则首先扩容,然后调用String的getChars()方法将str追加到value末尾。最后返回对象本身,所以append()可以连续调用。

三、StringBuilder

AbstractStringBuilder已经实现了大部分需要的方法,StringBuilder和StringBuffer只需要调用即可。下面来看看StringBuilder的实现。

1、构造器

?
publicStringBuilder() {
  super(16);
}
publicStringBuilder(intcapacity) {
  super(capacity);
}
publicStringBuilder(String str) {
  super(str.length() + 16);
  append(str);
}
publicStringBuilder(CharSequence seq) {
  this(seq.length() + 16);
  append(seq);
}

可以看出,StringBuilder默认的容量大小为16。当然也可以指定初始容量,或者以一个已有的字符序列给StringBuilder对象赋初始值。

2、append()方法

?
publicStringBuilder append(String str) {
  super.append(str);
  returnthis;
}
publicStringBuilder append(CharSequence s) {
  super.append(s);
  returnthis;
}

append()的重载方法很多,这里随便列举了两个。显然,这里是直接调用的父类AbstractStringBuilder中的方法。

3、toString()

?

publicString toString() {
  // Create a copy, don't share the array
  returnnew String(value, 0, count);
}

toString()方法返回了一个新的String对象,与原来的对象不共享内存。其实AbstractStringBuilder中的subString()方法也是如此。

四、SringBuffer

StiringBuffer跟StringBuilder类似,只不过为了实现同步,很多方法使用lSynchronized修饰,如下面的方法:

?
publicsynchronized int length() {
    returncount;
}
publicsynchronized StringBuffer append(String str) {
  toStringCache = null;
  super.append(str);
  returnthis;
}
publicsynchronized void setLength(intnewLength) {
  toStringCache = null;
  super.setLength(newLength);
}

可以看到,方法前面确实加了Synchronized。
另外,在上面的append()以及setLength()方法里面还有个变量toStringCache。这个变量是用于最近一次toString()方法的缓存,任何时候只要StringBuffer被修改了这个变量会被赋值为null。StringBuffer的toString如下:

?

publicsynchronized String toString() {
  if(toStringCache == null) {
    toStringCache = Arrays.copyOfRange(value, 0, count);
  }
  returnnew String(toStringCache, true);
}

在这个方法中,如果toStringCache为null则先缓存。最终返回的String对象有点不同,这个构造方法还有个参数true。找到String的源码看一下:

?
String(char[] value, booleanshare) {
  // assert share : "unshared not supported";
  this.value = value;
}

原来这个构造方法构造出来的String对象并没有实际复制字符串,只是把value指向了构造参数,这是为了节省复制元素的时间。不过这个构造器是具有包访问权限,一般情况下是不能调用的。

总结

  • StringBuilder和StringBuffer都是可变字符串,前者线程不安全,后者线程安全。
  • StringBuilder和StringBuffer的大部分方法均调用父类AbstractStringBuilder的实现。其扩容机制首先是把容量变为原来容量的2倍加2。最大容量是Integer.MAX_VALUE,也就是0x7fffffff。
  • StringBuilder和StringBuffer的默认容量都是16,最好预先估计好字符串的大小避免扩容带来的时间消耗。
0
0
查看评论

StringBuffer 与 StringBuilder 区别与联系及源码分析

StringBuffer和StringBuilder的共同点: 1、都是用于操作字符串,使用这两个而不使用String的原因是因为String是Final类型,当对字符串操作较多时采用StringBuffer或者StringBuilder。 String Final源码,在创建S...
  • u010854517
  • u010854517
  • 2017-03-08 10:07
  • 229

String、StringBuilder、 StringBuffer 深入分析 源码解析

java学习有一段时间了,但学习的东西都是框架等东西,java基础知识有点遗忘,所以重温一下java基础知识,写写文章里面有错的希望大家指正共同进步~~ 一、String 大家经常会说使用“+”号连接String 字符串比StringBuffer慢,String类对象为不可变对象,一旦你修改了S...
  • QH_JAVA
  • QH_JAVA
  • 2015-06-06 11:32
  • 6022

String ,StringBuffer和StringBuilder最佳用法

String  首先我们要明确,String并不是基本数据类型,而是一个对象,并且是不可变的对象。查看源码就会发现String类为final型的(当然也不可被继承),而且通过查看JDK文档会发现几乎每一个修改String对象的操作,实际上都是创建了一个全新的String对象。 ...
  • Jo__yang
  • Jo__yang
  • 2016-06-14 19:56
  • 626

String、StringBuffer、StringBuilder的区别与效率比较

String 是不可变的,StringBuffer、StringBuilder是可变的 String 、StringBuffer是线程安全的,StringBuilder是线程不安全的 (StringBuffer的append操作用了synchronized) 执行时间比较: ① String s ...
  • u010002184
  • u010002184
  • 2017-05-18 15:15
  • 416

StringBuilder的用法及String,StringBuffer与StringBuilder的区别

声明:本文大部分内容为参考别人的,自己简单汇总整理了一下。String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全)简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变...
  • u011489043
  • u011489043
  • 2017-03-30 15:33
  • 540

String,StringBuffer, StringBuilder类的常用方法

一、String类的常用方法1.获取: 1)获取字符串str长度 int i = str.length(); 2)根据位置(index)获取字符 char c = str.charAt(inde...
  • zhao_yu_lei
  • zhao_yu_lei
  • 2017-05-12 13:38
  • 770

String,StringBuffer,StringBuilder运行速度的比较

1.String 是final对象,不会被修改,每次使用 + 进行拼接都会创建新的对象,而不是改变原来的对象; 2.StringBuffer 可变字符串,主要用于字符串的拼接,属于线程安全的; 3.StringBuilder 可变字符串,主要用于字符串的拼接,属于线程不安全的; 可通过以下代码...
  • huwenhu2007
  • huwenhu2007
  • 2014-03-07 10:03
  • 3413

StringBuffer与StringBuilder之间的区别

public class Test { public static void main(String[] args) { StringBuffer strBuffer = new StringBuffer(); strBuffer.append("StringBuffer&quo...
  • a19881029
  • a19881029
  • 2014-03-02 13:25
  • 2587

String StringBuilder StringBuffer 对比 总结得非常好

转自:http://www.iteye.com/topic/522167 作者:每次上网冲杯Java时,都能看到关于String无休无止的争论。还是觉得有必要让这个讨厌又很可爱的String美眉,赤裸裸的站在我们这些Java色狼面前了。嘿嘿.... 众所周知,
  • clam_clam
  • clam_clam
  • 2011-09-28 19:00
  • 33214

Java基础之String、StringBuffer与StringBuilder的区别及应用场景

1 String、StringBuffer与StringBuilder (1)String 字符串常量; /** Strings are constant; their values cannot be changed after they * are created. String bu...
  • chenliguan
  • chenliguan
  • 2016-07-14 18:35
  • 6241
    个人资料
    • 访问:172665次
    • 积分:3522
    • 等级:
    • 排名:第11155名
    • 原创:156篇
    • 转载:250篇
    • 译文:2篇
    • 评论:14条
    最新评论