前言
本文针对于String类型相似的StringBuffer和 sertStringBuilder类的区别及StringBuffer和StringBuilder 类扩容,源码分析其中区别。
String、StringBuffer、StringBuilder三者异同
| String |
stringBuffer |
StringBuilder |
| 不可变 |
可变 |
可变 |
|
线程安全 |
线程不安全 |
| |
多线程操作字符串 |
单线程操作字符串 |
String
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
/**
* A <tt>CharSequence</tt> is a readable sequence of <code>char</code> values. This
* interface provides uniform, read-only access to many different kinds of
* <code>char</code> sequences.
* A <code>char</code> value represents a character in the <i>Basic
* Multilingual Plane (BMP)</i> or a surrogate. Refer to <a
* href="Character.html#unicode">Unicode Character Representation</a> for details.
*
* <p> This interface does not refine the general contracts of the {@link
* java.lang.Object#equals(java.lang.Object) equals} and {@link
* java.lang.Object#hashCode() hashCode} methods. The result of comparing two
* objects that implement <tt>CharSequence</tt> is therefore, in general,
* undefined. Each object may be implemented by a different class, and there
* is no guarantee that each class will be capable of testing its instances
* for equality with those of the other. It is therefore inappropriate to use
* arbitrary <tt>CharSequence</tt> instances as elements in a set or as keys in
* a map. </p>
*/
public interface CharSequence
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间。
特点
- String类是被final修饰的,是不能被继承的。
- String类底层使用数组结构。jdk9以前使用的是char[],jdk9以后使用的是byte[]。
- String的对象一旦创建就不能修改,底层维护了一个字符串常量池,实现共享。
StringBuffer
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
/**
* A mutable sequence of characters.
* <p>
* Implements a modifiable string. 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.
*/
abstract class AbstractStringBuilder implements Appendable, CharSequence
/**
* An object to which <tt>char</tt> sequences and values can be appended. The
* <tt>Appendable</tt> interface must be implemented by any class whose
* instances are intended to receive formatted output from a {@link
* java.util.Formatter}.
*
* <p> The characters to be appended should be valid Unicode characters as
* described in <a href="Character.html#unicode">Unicode Character
* Representation</a>. Note that supplementary characters may be composed of
* multiple 16-bit <tt>char</tt> values.
* <p> Appendables are not necessarily safe for multithreaded access. Thread
* safety is the responsibility of classes that extend and implement this
* interface.
* <p> Since this interface may be implemented by existing classes
* with different styles of error handling there is no guarantee that
* errors will be propagated to the invoker.
*/
public interface Appendable
StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。
特点
StringBuffer常用方法:
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 {@code capacity}
* argument is less than {@code 0}.
*/
public StringBuffer(int capacity) {
super(capacity);
}
/**
* Constructs a string buffer initialized to the contents of the
* specified string. The initial capacity of the string buffer is
* {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
*/
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
/**
* Constructs a string buffer that contains the same characters
* as the specified {@code CharSequence}. The initial capacity of
* the string buffer is {@code 16} plus the length of the
* {@code CharSequence} argument.
* <p>
* If the length of the specified {@code CharSequence} is
* less than or equal to zero, then an empty buffer of capacity
* {@code 16} is returned.
*
* @param seq the sequence to copy.
* @since 1.5
*/
public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
@Override
public synchronized int length() {
return count;
}
@Override
public synchronized int capacity() {
return value.length;
}
@Override
public synchronized void ensureCapacity(int minimumCapacity) {
super.ensureCapacity(minimumCapacity);
}
@Override
public synchronized void trimToSize() {
super.trimToSize();
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/
@Override
public synchronized void setLength(int newLength) {
toStringCache = null;
super.setLength(newLength);
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/
@Override
public synchronized char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}
@Override
public synchronized int codePointAt(int index) {
return super.codePointAt(index);
}
@Override
public synchronized int codePointBefore(int index) {
return super.codePointBefore(index);
}
@Override
public synchronized int codePointCount(int beginIndex, int endIndex) {
return super.codePointCount(beginIndex, endIndex);
}
StringBuilder
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
StringBuilder是可变类,和线程不安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuilder对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。
特点
StringBuilder常用方法:
/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
/**
* Constructs a string builder with no characters in it and an
* initial capacity specified by the {@code capacity} argument.
*
* @param capacity the initial capacity.
* @throws NegativeArraySizeException if the {@code capacity}
* argument is less than {@code 0}.
*/
public StringBuilder(int capacity) {
super(capacity);
}
/**
* Constructs a string builder initialized to the contents of the
* specified string. The initial capacity of the string builder is
* {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
*/
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
/**
* Constructs a string builder that contains the same characters
* as the specified {@code CharSequence}. The initial capacity of
* the string builder is {@code 16} plus the length of the
* {@code CharSequence} argument.
*
* @param seq the sequence to copy.
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder deleteCharAt(int index) {
super.deleteCharAt(index);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder replace(int start, int end, String str) {
super.replace(start, end, str);
return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder insert(int index, char[] str, int offset,
int len)
{
super.insert(index, str, offset, len);
return this;
}
@Override
public int indexOf(String str) {
return super.indexOf(str);
}
@Override
public StringBuilder reverse() {
super.reverse();
return this;
}
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
/**
* Save the state of the {@code StringBuilder} instance to a stream
* (that is, serialize it).
*
* @serialData the number of characters currently stored in the string
* builder ({@code int}), followed by the characters in the
* string builder ({@code char[]}). The length of the
* {@code char} array may be greater than the number of
* characters currently stored in the string builder, in which
* case extra characters are ignored.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeInt(count);
s.writeObject(value);
}
/**
* readObject is called to restore the state of the StringBuffer from
* a stream.
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
count = s.readInt();
value = (char[]) s.readObject();
}
StringBuffer和StringBuilder的初始容量及扩容
StringBuffer和StringBuilder初始的空闲容量都是16,当调用append方法时调用的都是super.append即AbstractStringBuilder中方法,所以扩容机制相同。
StringBuffer类有StringBuffer(),StringBuffer(int capacity),StringBuffer(String str)三个改造方法。
StringBuffer()的初始容量可以容纳16个字符,当该对象的实体存放的字符的长度大于16时,实体容量就自动增加。StringBuffer对象可以通过length()方法获取实体中存放的字符序列长度,通过capacity()方法来获取当前实体的实际容量。
public StringBuilder() {
super(16);
}
StringBuffer(int capacity)可以指定分配给该对象的实体的初始容量参数为参数size指定的字符个数。当该对象的实体存放的字符序列的长度大于size个字符时,实体的容量就自动的增加。以便存放所增加的字符。
public StringBuilder(int capacity) {
super(capacity);
}
StringBuffer(String str)可以指定给对象的实体的初始容量为参数字符串s的长度额外再加16个字符。当该对象的实体存放的字符序列长度大于size个字符时,实体的容量自动的增加,以便存放所增加的字符。
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
StringBuffer怎样扩容: StringBuffer通过append方法中的ensureCapacityInternal方法可以看出当追加后超出容量会触发扩容,通过newCapacity获得新容量。
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;
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
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;
}
- 如果要操作少量的数据用 String;
- 多线程操作字符串缓冲区下操作大量数据 StringBuffer
- 单线程操作字符串缓冲区下操作大量数据 StringBuilder;
- StringBuffer和StringBuilder的区别就在于StringBuffer的操作使用synchronized关键字加了锁,是线程安全的。
总结:
1.由于StringBuilder和StringBuffer继承了AbstractStringBuilder ,所以StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象;而String的值是不可变的,每次对String的操作都会生成新的String对象,这样不仅效率低下,而且大量浪费有限的内存空间。
2.每个StringBuffer、StringBuilder对象都有一定的缓冲区容量(==初始大小为16==),当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。
3.StringBuffer中的方法都有synchronized关键字修饰,而StringBuilder没有,所以StringBuffer线程安全,而StringBuilder线程不安全。