下面這條語句一共建立了多少個物件:String s="a"+"b"+"c"+"d";
最近看到許多類似的帖子,大致意思如下:
問題1: String s = “a” + “b” + “c” + “d” + “e”; 問此語句共建立了幾個物件?
答:就建立了一個
解析:String s = “a” + “b” + “c” + “d” + “e”;
賦值符號右邊的"a"、“b”、“c”、“d”、“e"都是常量
對於常量,編譯時就直接儲存它們的字面值而不是它們的引用
在編譯時就直接將它們連線的結果提取出來變成了"abcde”
該語句在class檔案中就相當於String s = “abcde”
然後當JVM執行到這一句的時候, 就在String pool裡找
如果沒有這個字串,就會產生一個
問題2:如果改成 String s = a+b+c+d+e; 呢,又是幾個了?
(就是說上面是一個是因為 “a”、“b”、“c”、“d”、"e"都是常量,但如果是變數呢? )
答:是3個物件,但只有一個String物件。
由於編譯器的優化,最終程式碼為通過StringBuilder完成:
StringBuilder builder = new StringBuilder();
builder.append(a);
builder.append(b);
builder.append(c);
builder.append(d);
builder.append(e);
String s = builder.toString();
我們先看看StringBuilder的構造器
public StringBuilder() {
super(16);
}
//看下去
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
可見,分配了一個16位元組長度的char陣列
我們看看append的整個過程
(注意:原始碼我從各個類進行了整合,他們實際上不在一個類裡面的)
public StringBuilder append(String str) {
super .append(str);
return this;
}
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;
}
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);
}
可見,我們的程式碼不會超過16個,所以不會出現擴充套件value的情況。
而append裡面使用了arraycopy的複製方式,也沒有產生新的物件。
最後,我們再看StringBuilder的 toString()方法:
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
//這裡通過前面的陣列生成了一個新的String。
大家注意那個預設的16容量,如果題目出現了總長度超過16,則會出現如下的再次分配的情況
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System
.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
}
可見,expand容量時,增加為當前(長度+1)*2。
注意:這裡用了Arrays的方法,注意不是前面的 System.arraycopy方法哦。這裡產生了一個新的copy的char陣列,長度為新的長度。
總結:三個物件分別為
1 StringBuilder
2 new char[capacity]
3 new String(value,0,count);
如果說String物件,則為1個。
作者:老紫竹