平時我們一般涉及到字符串的拼接,最本能最直接的方法就是+.
String s1 = "Hello";
s1=s1+"word";
當數據拼接次數比較少的時候,這樣的方法無可厚非,但是一旦次數較多時,這樣的方法效率很低,而且浪費大量的空間
現在我要講的是String,StringBuilder,StringBuffer,這三個有什麼區別,以及平時我們使用時該注意什麼?
1.String
String的值是不可變的,這就導致每次對String的操作都會生成新的String對象,不僅效率低下,而且大量浪費有限的內存空間。
爲什麼會浪費大量的空間?
看上面的代碼,假設s1指向地址0x0001 ,當重新賦值後s1指向的地址是0x0002了,然而地址0x0001裏保存的s1依然存在,這就導致了每次重新賦值,就會產生一個新的地址指向,而原來的不會消失,浪費了大量的空間。因此String的操作都是改變賦值地址而不是改變值操作。
2. StringBuffer
StringBuffer是可變類和線程安全的字符串操作類,任何對它指向的字符串的操作都不會產生新的對象。 每個StringBuffer對象都有一定的緩衝區容量,當字符串大小沒有超過容量時,不會分配新的容量,當字符串大小超過容量時,會自動增加容量。
/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
/**
* 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);
}
看上面的源碼我們會發現
StringBuffer buf=new StringBuffer(); //分配長16字節的字符緩衝區
StringBuffer buf=new StringBuffer("this"); //分配長"this".length()+16字節的字符緩衝區
StringBuffer buf=new StringBuffer("this")//在緩衝區中存放了字符串,並在後面預留了16字節的空緩衝區。
那麼字符串大小超過容量時是怎麼擴容的呢?
這可能就涉及到其常用的append方法了
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
// Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return appendNull();
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
}
/**
* For positive values of {@code minimumCapacity}, this method
* behaves like {@code ensureCapacity}, however it is never
* synchronized.
* If {@code minimumCapacity} is non positive due to numeric
* overflow, this method throws {@code OutOfMemoryError}.
*/
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
/**
* Returns a capacity at least as large as the given minimum capacity.
* Returns the current capacity increased by the same amount + 2 if
* that suffices.
* Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
* unless the given minimum capacity is greater than that.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero or
* greater than Integer.MAX_VALUE
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;(value.length << 1表示原來的2倍,這個是二進制寫法後的轉換問題)
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
看上面的源碼會發現擴容到原來的兩倍+2的長度,如果還是不夠的話就用到了minimumCapacity=count+len這個長度