字符串拼接
字符串拼接,之前使用的"字符串"+"字符串"的方式,但是会在字符串常量池中生成大量的字符串对象,因此,在字符串的拼接中,一般使用StringBuffer火StringBuilder。
首先需要了解为啥字符串常量无法更改,通过查看String类源码,会发现如下代码:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[];
可以看到,字符串是通过一个常量数组存储的,这就是无法更改的原因。那为何StringBuffer就可以取得更好的效果呢?在查看StringBuffer的相关源码后:
/** * A cache of the last value returned by toString. Cleared * whenever the StringBuffer is modified. */ private transient char[] toStringCache; /** use serialVersionUID from JDK 1.0.2 for interoperability */ static final long serialVersionUID = 3388685877147921107L; /** * 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 {@code capacity} * argument is less than {@code 0}. */ public StringBuffer(int capacity) { super(capacity); }
再次查找其父类: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]; }
会发现有几个不同点,第一,它仍然是通过一个数组进行存储,但是,不是final,而且还提供了一个用来缓存的数组;第二,这个数组有一个长度,初始大小为16;
通过使用append方法拼接字符串,前面也说过,由于数组长度限制了,那拼接时就会超过这个长度,那应该如何解决?
查看append方法源码:
@Override public synchronized StringBuffer append(Object obj) { toStringCache = null; super.append(String.valueOf(obj)); return this; } @Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } @Override public synchronized StringBuffer append(CharSequence s) { toStringCache = null; super.append(s); return this; }
继续查看其父类:
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; }
查看ensureCapacityInternal()这个方法:
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); }
会发现:
value = Arrays.copyOf(value, newCapacity);也就是说,进行了数组扩容
StringBuffer和StringBuilder都可以用来拼接字符串,区别是,安全性不同,查看源码后会发现StingBuffer的成员方法均含有关键字“synchronized ”,而StringBuilder没有
即StringBuffer时线程安全的