java數組複製 System.copyarray()方法
System.copyarray()方法可以用來複制數組,其格式是:
System.arraycopy(Object src, int src_position, Object dst, int dst_position, int length)
它將數組從src 複製到dst,複製的位置是src 的第src_position 個元素到dst 的第dst_position
位置,複製元素的個數爲length。
注意:該方法只複製元素。如果數組元素是引用型變量,則只複製引用,不復制對象
實體。
StringBuffer 字符串變量(線程安全)
StringBuilder 字符串變量(非線程安全)
String 類型和 StringBuffer 、StringBuilder 類型的主要性能區別其實在於 String 是不可變的對象,而後倆者都是可變的。
來看看 StringBuffer類源碼定義:
-
- public finalclass StringBuffer
- extends AbstractStringBuilder
- implements java.io.Serializable, CharSequence
- {
-
- public StringBuffer() {
- super(16);
- }
-
- public StringBuffer(int capacity) {
- super(capacity);
- }
- <STRONG>
- public final class StringBuffer
- extends AbstractStringBuilder
- implements java.io.Serializable, CharSequence
- {
-
- public StringBuffer() {
- super(16);
- }
-
- public StringBuffer(int capacity) {
- super(capacity);
- }
- </STRONG>
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
public StringBuffer() {
super(16);
}
public StringBuffer(int capacity) {
super(capacity);
}
上例代碼我們發現 StringBuffer 繼承了 AbstractStringBuilder抽象類。包括構造方法的實現,都是父類提供的。
然後,我們打開 StringBuilder源碼定義:
- public finalclass StringBuilder
- extends AbstractStringBuilder
- implements java.io.Serializable, CharSequence
- {
-
- public StringBuilder() {
- super(16);
- }
-
- public StringBuilder(int capacity) {
- super(capacity);
- }
- <STRONG>public final class StringBuilder
- extends AbstractStringBuilder
- implements java.io.Serializable, CharSequence
- {
-
- public StringBuilder() {
- super(16);
- }
-
- public StringBuilder(int capacity) {
- super(capacity);
- }
- </STRONG>
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
public StringBuilder() {
super(16);
}
public StringBuilder(int capacity) {
super(capacity);
}
我們發現兩者都繼承了AbstractStringBuilder抽象類。且構造方法都調用父類實現。
我們接着看兩者append方法實現:
先看StringBuffer的:
-
- public synchronized StringBuffer append(Object obj) {
- super.append(String.valueOf(obj));
- return this;
- }
-
- public synchronized StringBuffer append(String str) {
- super.append(str);
- return this;
- }
-
- <STRONG>
- public synchronized StringBuffer append(Object obj) {
- super.append(String.valueOf(obj));
- return this;
- }
-
- public synchronized StringBuffer append(String str) {
- super.append(str);
- return this;
- }
-
- </STRONG>
public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj));
return this;
}
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
//...
再看StringBuilder的:
- public StringBuilder append(Object obj) {
- return append(String.valueOf(obj));
- }
-
- public StringBuilder append(String str) {
- super.append(str);
- return this;
- }
-
- <STRONG>
- public StringBuilder append(Object obj) {
- return append(String.valueOf(obj));
- }
-
- public StringBuilder append(String str) {
- super.append(str);
- return this;
- }
-
- </STRONG>
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
//...
對比上面兩段源碼 我們發現 StirngBuffer 和StringBuilder的 append實現都是調用父類實現的。唯一不同的是 StringBuffer是線程安全的,方法中多了synchronized ,而StringBuilder 是非線程安全的。
我們看下父類AbstractStringBuilder 定義 及 append 實現:
- abstract class AbstractStringBuilderimplements Appendable, CharSequence {
-
- char value[];
-
- int count;
-
- AbstractStringBuilder() {
- }
-
- AbstractStringBuilder(int capacity) {
- value = new char[capacity];
- }
- <STRONG>abstract class AbstractStringBuilder implements Appendable, CharSequence {
-
- char value[];
-
- int count;
-
- AbstractStringBuilder() {
- }
-
- AbstractStringBuilder(int capacity) {
- value = new char[capacity];
- }
- </STRONG>
abstract class AbstractStringBuilder implements Appendable, CharSequence {
//底層與String類一樣都是 char類型數組。
char value[];
//字符串長度
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
- public AbstractStringBuilder append(Object obj) {
- return append(String.valueOf(obj));
- }
-
- public AbstractStringBuilder append(String str) {
-
- if (str == null) str ="null";
- int len = str.length();
- if (len == 0)return
this;
-
- int newCount = count + len;
- if (newCount > value.length)
-
- expandCapacity(newCount);
-
- str.getChars(0, len, value, count);
- count = newCount;
- return this;
- }
-
-
- void expandCapacity(int minimumCapacity) {
-
- int newCapacity = (value.length +1) *
2;
-
-
- if (newCapacity <
0) {
- newCapacity = Integer.MAX_VALUE;
- } else if (minimumCapacity > newCapacity) {
- newCapacity = minimumCapacity;
- }
- char newValue[] =
new char[newCapacity];
-
- System.arraycopy(value, 0, newValue,0, count);
- value = newValue;
- }
-
- public void getChars(int srcBegin,int srcEnd,
char dst[],int dstBegin) {
- if (srcBegin < 0) {
- throw new StringIndexOutOfBoundsException(srcBegin);
- }
- if (srcEnd > count) {
- throw new StringIndexOutOfBoundsException(srcEnd);
- }
- if (srcBegin > srcEnd) {
- throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
- }
- System.arraycopy(value, offset + srcBegin, dst, dstBegin,
- srcEnd - srcBegin);
- }
StringBuffer與StringBuilder是java.lang包下被大家熟知的兩個類。其異同爲:一、長度都是可擴充的;二、StringBuffer是線程安全的,StringBuilder是線程不安全的。那麼他們的長度是如何實現動態擴充以及StringBuffer的線程安全是如何實現的呢?通過“深度”閱讀它們的源代碼,最終弄明白其中的緣由。
正文
首先上一張StringBuffer和StringBuilder類結構圖:
抽象類AbstractStringBuilder(也是核心實現類)實現了Appendable和CharSequence兩個接口;StringBuffer與StringBuilder統統繼承自AbstractStringBuilder,並且實現了java.io.Serializable和CharSequence接口。
下面簡單描述下這幾個接口所起到的作用(引用自中文api)。
- Appendable:能夠被添加 char 序列和值的對象。如果某個類的實例打算接收java.util.Formatter
的格式化輸出,那麼該類必須實現 Appendable 接口
。要添加的字符應該是有效的 Unicode 字符,正如 Unicode Character
Representation 中描述的那樣。注意,增補字符可能由多個 16 位char 值組成- CharSequence:CharSequence 是 char 值的一個可讀序列。此接口對許多不同種類的 char 序列提供統一的只讀訪問。char 值表示 Basic Multilingual Plane (BMP) 或代理項中的一個字符。有關詳細信息,請參閱Unicode
字符表示形式。此接口不修改equals
和hashCode 方法的常規協定。因此,通常未定義比較實現
CharSequence 的兩個對象的結果。每個對象都可以通過一個不同的類實現,而且不能保證每個類能夠測試其實例與其他類的實例的相等性。因此,使用任意 CharSequence 實例作爲集合中的元素或映射中的鍵是不合適的。
- Serializable:類通過實現 java.io.Serializable 接口以啓用其序列化功能。未實現此接口的類將無法使其任何狀態序列化或反序列化。可序列化類的所有子類型本身都是可序列化的。序列化接口沒有方法或字段,僅用於標識可序列化的語義。
r這個抽象類提供了StringBuffer和StringBuilder絕大部分的實現。在AbstractStringBuilder的描述中說:如果去掉線程安全,那麼StringBuffer和StringBuilder是完全一致的。從實現的角度來說,StringBuffer所有方法(構造方法除外,因爲沒有必要)簽名中都使用synchronized限定,也就是所有的方法都是同步的。eg.StringBuffer中replace()方法
1 |
public synchronized StringBuffer replace( int start,
int end, String str) { |
2 |
super .replace(start, end, str); |
StringBuilder中replace():
1 |
public StringBuilder replace( int start,
int end, String str) { |
2 |
super .replace(start, end, str); |
區別僅僅在方法簽名上是否有synchronized。
另外需要稍稍注意的問題是:StringBuffer同步只同步目標,比如:sb.append("i am not synchronized"),sb是同步的,而其中的參數未必是同步的。
而它們兩個可擴展長度則是通過ensureCapacity(int minimumCapacity)來驗證當前長度是否小於參數minimumCapacity,如果成立則進行分配空間。分配新空間的步長爲(當前長度+1)的兩倍。
實現如下:
01 |
public void ensureCapacity( int minimumCapacity) { |
02 |
if (minimumCapacity > value.length) { |
03 |
expandCapacity(minimumCapacity); |
06 |
void expandCapacity( int
minimumCapacity) { |
07 |
int newCapacity = (value.length + 1 ) * 2 ; |
08 |
if (newCapacity < 0 ) { |
09 |
newCapacity = Integer.MAX_VALUE; |
10 |
} else if (minimumCapacity > newCapacity) { |
11 |
newCapacity = minimumCapacity; |
13 |
value = Arrays.copyOf(value, newCapacity); |
如果新的長度小於0(溢出了),則使用Integer的最大值作爲長度。
另外,在閱讀源碼的過程中,發現兩個有趣的問題,下面一一道來。
第一個,就是reverse的實現。其實我是第一次看StringBuilder和StringBuffer的源碼,這裏面的reverse的實現是我所知道的java中的最高效的實現,沒有之一。
上源碼,再做解釋:
01 |
public AbstractStringBuilder reverse() { |
02 |
boolean hasSurrogate = false ; |
04 |
for ( int j = (n- 1 ) >> 1 ; j >=
0 ; --j) { |
06 |
char temp2 = value[n - j]; |
08 |
hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE) |
09 |
|| (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE); |
15 |
// Reverse back all valid surrogate pairs |
16 |
for ( int i = 0 ; i < count - 1 ; i++) { |
18 |
if (Character.isLowSurrogate(c2)) { |
19 |
char c1 = value[i + 1 ]; |
20 |
if (Character.isHighSurrogate(c1)) { |
reverse分成兩個部分:前面一個循環與後面的判斷。
首先地一個循環很高效,循環次數爲長度(count)的一半,而且使用>>位移運算,交換數組value[j]與value[n-j]的值。這裏一是循環次數少,而是使用最高效的位移運算所以說這個reverse很高效。在反轉過程中還完成了一件事:就是爲hasSurrogate賦值。賦值的依據就是value[j]與value[n-j]兩個字符時候有一個在\uD800和\uDFFF之間,如果有則賦值爲true。
- <STRONG>
- public AbstractStringBuilder append(Object obj) {
- return append(String.valueOf(obj));
- }
-
- public AbstractStringBuilder append(String str) {
-
- if (str == null) str = "null";
- int len = str.length();
- if (len == 0) return this;
-
- int newCount = count + len;
- if (newCount > value.length)
-
- expandCapacity(newCount);
-
- str.getChars(0, len, value, count);
- count = newCount;
- return this;
- }
-
-
- void expandCapacity(int minimumCapacity) {
-
- int newCapacity = (value.length + 1) * 2;
-
-
- if (newCapacity < 0) {
- newCapacity = Integer.MAX_VALUE;
- } else if (minimumCapacity > newCapacity) {
- newCapacity = minimumCapacity;
- }
- char newValue[] = new char[newCapacity];
-
- System.arraycopy(value, 0, newValue, 0, count);
- value = newValue;
- }
-
- public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
- if (srcBegin < 0) {
- throw new StringIndexOutOfBoundsException(srcBegin);
- }
- if (srcEnd > count) {
- throw new StringIndexOutOfBoundsException(srcEnd);
- }
- if (srcBegin > srcEnd) {
- throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
- }
- System.arraycopy(value, offset + srcBegin, dst, dstBegin,
- srcEnd - srcBegin);
- }
- </STRONG>
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public AbstractStringBuilder append(String str) {
//對於str==null的
if (str == null) str = "null";
int len = str.length();
if (len == 0) return this;
//新的字符串長度
int newCount = count + len;
if (newCount > value.length)
//當新的字符串長度比原先數組長度大時,需要對char 數組擴容。
expandCapacity(newCount);
//將新添的數據追加到char類型數組中。
str.getChars(0, len, value, count);
count = newCount;
return this;
}
//數組擴容
void expandCapacity(int minimumCapacity) {
//先擴容成 (原先的長度+1)*2
int newCapacity = (value.length + 1) * 2;
//判斷newCapacity值是否滿足要求
//如果新的長度還是不夠,則直接取值 minimumCapacity
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
char newValue[] = new char[newCapacity];
//將原先的數據拷貝到新的char 數組中。
System.arraycopy(value, 0, newValue, 0, count);
value = newValue;
}
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > count) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, offset + srcBegin, dst, dstBegin,
srcEnd - srcBegin);
}