本博文主要是介绍一下String、StringBuffer和StringBuilder之间的区别和联系。
1、从类的定义看StringBuffer、StringBuilder、String的关系
首先来看一下源码中这几个类的定义如下:
//CharSequence定义
public interface CharSequence
//StringBuffer定义
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
//StringBuilder定义
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
//String定义
public final class String
implements
java.io.Serializable, Comparable<String>, CharSequence
注意:String、StringBuffer、StringBuilder都是final类型的,这意味着它们是不能被其它类继承的(我哥们去阿里面试的时候被问过)
由以上源码定义我们可以得到三者之间的关系图如下所示:
可以发现三者都实现了CharSequence接口,CharSequence其实也就是定义了字符串操作的接口,这个接口包含length(), charAt(int index),
subSequence(int start, int end)这几个API接口。而StringBuilder和StringBuffer都继承自AbstractStringBuilder类。
2、从构造函数到具体的字符串拼接操作看看String、StringBuffer、StringBuilder的区别
2.1String的构造函数
public String() {
this.offset = 0;
this.count = 0;
this.value = new char[0];
}
/**
* Initializes a newly created {@code String} object so that it represents
* the same sequence of characters as the argument; in other words, the
* newly created string is a copy of the argument string. Unless an
* explicit copy of {@code original} is needed, use of this constructor is
* unnecessary since Strings are immutable.
*
* @param original
* A {@code String}
*/
public String(String original) {
int size = original.count;
char[] originalValue = original.value;
char[] v;
if (originalValue.length > size) {
// The array representing the String is bigger than the new
// String itself. Perhaps this constructor is being called
// in order to trim the baggage, so make a copy of the array.
int off = original.offset;
v = Arrays.copyOfRange(originalValue, off, off + size);
} else {
// The array representing the String is the same
// size as the String, so no point in making a copy.
v = originalValue;
}
this.offset = 0;
this.count = size;
this.value = v;
}
/**
* Allocates a new {@code String} so that it represents the sequence of
* characters currently contained in the character array argument. The
* contents of the character array are copied; subsequent modification of
* the character array does not affect the newly created string.
*
* @param value
* The initial value of the string
*/
public String(char[] value) {
this.offset = 0;
this.count = value.length;
this.value = StringValue.from(value);
}
再看看String类中的contact()函数——
将指定字符串联到此字符串的结尾。
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
char[] buf = new char[count + otherLen];
getChars(0, count, buf, 0);
str.getChars(0, otherLen, buf, count);
return new String(0, count + otherLen, buf);
}
从Concat函数中,我们可以知道在对字符串使用concat操作后,具体的操作new出一个等同于两个字符串连接总长度的新的char数组,然后将两个字符串复制到新的char数组中,然后返回一个新的String对象。
2.2StringBuilder常见构造函数
public StringBuffer() {
super(16);
}
public StringBuffer(int capacity) {
super(capacity);
}
从StringBuilder的构造函数中,我们可以看见StringBuilder直接调用父类(AbstractStringBuilder)的构造函数,我们再看AbstractStringBuilder的构造函数。
abstract class AbstractStringBuilder implements Appendable, CharSequence {
final static int[] sizeTable = {
9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999,
Integer.MAX_VALUE
};
/**
* 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];
}
//其他的一些逻辑
}
从AbstractStringBuilder的构造函数中,我们可以看出StringBuilder中存储字符串其实用的是一个char数组,capacity其实就是指定这个char数组的大小。
下面我们再从StringBuilder中的append函数看看他具体是怎么做的(以 append(String str) 为例看看)。
public StringBuilder append(String str) {
super.append(str);
return this;
}
来看看AbstractStringBuilder类中的append()函数
/**
* value 用来存储字符串.
*/
char value[];
/**
* 有效字符串的数目.
*/
int count;
public AbstractStringBuilder append(String str) {
if (str == null) {
str = "null";
}
int len = str.length();
if (len == 0) {
return this;
}
/**
* 判断原来用于存储字符串的values的字符串数组有没有足够的大小来存储将要新添加入StringBuilder的字符串。如果不够用,那么就调用expandCapacity(int minimumCapacity)让容量翻两倍
*/
int newCount = count + len;
if (newCount > value.length) {
expandCapacity(newCount);
}
//getChars将字符串复制到指定的位置
str.getChars(0, len, value, count);
count = newCount;
return this;
} 2.3 StringBuffer构造函数
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
/**
* Constructs a string buffer with no characters in it and
* the specified initial capacity.
*
* @param capacity the initial capacity.
* @exception NegativeArraySizeException if the capacity
* argument is less than 0.
*/
public StringBuffer(int capacity) {
super(capacity);
}
StringBuffer也是直接调用父类(AbstractStringBuilder)的构造函数(见上面)StringBuffer的append()函数
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
还是调用父类的append函数,但是在这里有值得注意的地方,StringBuffer的append函数有一个synchronized标识符,也就是说StringBuffer中的append函数是线程安全的,通过继续查阅其他StringBuffer中的函数,我们也可以发现他们有synchronized标识符,这就不难理解为什么StringBuffer是线程安全的,但是很明显加上线程控制会拖慢程序运行的速度,所以如果不需要线程控制,那么最好就用StringBuilder。
3.比较下三者之间的区别:
3.1StringBuffer和StringBuilder之间的区别和联系。
StringBuilder 和 StringBuffer都是可变的字符序列。它们都继承于AbstractStringBuilder,实现了CharSequence接口;StringBuilder是非线程安全的,而StringBuffer是线程安全的,但是很明显加上线程控制会拖慢程序运行的速度,所以如果不需要线程控制,那么最好就用StringBuilder。
3.2 String和StringBuffer、StringBuilder之间的区别。
StringBuffer和StringBuilder对象的内容可以修改;而String对象一旦产生后就不可以被修改,重新赋值其实是两个对象。StringBuffer(StringBuilder)的内部实现方式和String不同,StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类。所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入、删除等操作,使用StringBuffer要更加适合一些。StringBuffer对象的append效率要高于String对象的"+"连接操作。
参考:
http://www.cnblogs.com/kissazi2/p/3648671.html