public String(String original) {
int size = original.count;
char[] originalValue = original.value;
char[] v;
if (originalValue.length > size) { // 關鍵判斷
int off = original.offset;
v = Arrays.copyOfRange(originalValue, off, off + size);
} else {
v = originalValue;
}
this.offset = 0;
this.count = size;
this.value = v;
}
當且僅當 original 由 substring() 產生時,會出現 originalValue.length > size。此時新 String 會複製底層字符數組相關片段,實現內存隔離。
public String substring(int beginIndex, int endIndex) {
// 邊界檢查...
return ((beginIndex == 0) && (endIndex == count)) ? this
: new String(offset + beginIndex, endIndex - beginIndex, value); // 共享 value 數組
}
String(int offset, int count, char[] value) { // 包私有構造器
this.value = value;
this.offset = offset;
this.count = count;
}
String s1 = "hello world"; // value=['h','e','l','l','o',' ','w','o','r','l','d'], offset=0, count=11
String s2 = s1.substring(6); // value=同 s1.value, offset=6, count=5 ("world")
String s3 = new String(s2); // 觸發 originalValue.length(11) > size(5) -> 複製 ['w','o','r','l','d']
若不複製,
s3仍引用原 11 字符數組,導致s1無法被 GC 回收(即使s1不再使用)。複製後s3持有獨立 5 字符數組,s1可正常回收。
| 版本 | substring 行為 | String 構造器邏輯 |
|---|---|---|
| JDK 6 | 共享 char[] + offset/count | 檢測共享則複製 |
| JDK 7u6+ | 始終複製新 char[] | 無需檢測,直接複製 |
| JDK 9+ (Compact Strings) | byte[] + coder (LATIN1/UTF16) | 同 JDK 7,但操作 byte[] |