1. 程式人生 > >下面這條語句一共建立了多少個物件:String s="a"+"b"+"c"+"d";

下面這條語句一共建立了多少個物件: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個。


作者:老紫竹