2011-11-04 72 views
20

這是一個面試問題。我被要求執行StringBuffer附加功能。面試後我看到了代碼。但是我無法理解如何通過創建單個對象來完成操作。StringBuffer如何在不創建兩個對象的情況下實現append功能?

我正在這樣想。

String s = "orange"; 
s.append("apple"); 

這裏創建了兩個對象。

StringBuilder s = new StringBuilder("Orange"); 
s.append("apple"); 

現在這裏只創建一個對象。

Java如何進行此操作?

+0

中有問題的幾個假設這是不正確的。 'new StringBuilder()'和'new String()'創建兩個對象。 –

+3

是我的問題嗎? ;) –

回答

45

首先出現的是與你的問題一個問題:

String s = "orange"; 
s.append("apple"); 

這裏的兩個對象被創建

正確,創建了兩個對象,字符串「橙色」和字符串「蘋果「,在StringBuffer/StringBuilder內部,如果我們不溢出緩衝區,則不會創建對象。所以這些代碼行創建2或3個對象。

StringBuilder s = new StringBuilder("Orange"); 
s.append("apple"); 

現在,這裏只有一個對象被創建

我不知道你在哪裏得到的是,在這裏你創建一個StringBuilder對象,一個「橙色」字符串,一個「蘋果」字符串,總共有3個對象,如果我們溢出了StringBuilder緩衝區,則爲4。 (我將數組創建爲對象創建)。


我看了你的問題,StringBuilder的怎麼辦追加而不創建新的對象(如果緩衝區不溢出)?

你應該看看StringBuilder,因爲它是非線程安全的實現。代碼很有趣,很容易閱讀。我添加了內嵌評論。

作爲內部結構有一個char數組,而不是一個字符串。它最初建造的長度爲16,每次超過容量時都會增加。如果要在char數組中添加字符串,則不需要創建新的對象。

StringBuilder延伸AbstractStringBuilder,在那裏你會發現下面的代碼:

/** 
* The value is used for character storage. 
*/ 
char value[]; 

由於並非所有的陣列將在給定時間使用,另外一個重要的變量是長度:

/** 
* The count is the number of characters used. 
*/ 
int count; 

追加有很多超載,但最有趣的是以下幾種:

public AbstractStringBuilder append(String str) { 
    if (str == null) str = "null"; //will literally append "null" in case of null 
    int len = str.length(); //get the string length 
    if (len == 0) return this; //if it's zero, I'm done 
    int newCount = count + len; //tentative new length 
    if (newCount > value.length) //would the new length fit? 
     expandCapacity(newCount); //oops, no, resize my array 
    str.getChars(0, len, value, count); //now it will fit, copy the chars 
    count = newCount; //update the count 
    return this; //return a reference to myself to allow chaining 
} 

String.getChars(int srcBegin,int srcEnd,char [] dst,int dstBegin)將此字符串中的字符複製到目標字符數組中。

所以,追加方法相當簡單,這隻神奇的左邊發現是expandCapacity,那就是:

void expandCapacity(int minimumCapacity) { 
    //get the current length add one and double it 
    int newCapacity = (value.length + 1) * 2; 
    if (newCapacity < 0) { //if we had an integer overflow 
     newCapacity = Integer.MAX_VALUE; //just use the max positive integer 
    } else if (minimumCapacity > newCapacity) { //is it enough? 
     //if doubling wasn't enough, use the actual length computed 
     newCapacity = minimumCapacity; 
    } 
    //copy the old value in the new array 
    value = Arrays.copyOf(value, newCapacity); 
} 

Arrays.copyOf(的char []原來,INT newLength)複製指定的數組,截斷或填充空字符(如有必要),以便副本具有指定的長度。

在我們的例子中,填充,因爲我們正在擴大長度。

+3

你能解釋爲什麼在expandCapacity中,首先將value.length增加1,然後再乘以2?是否需要增加1來說明空字符 – CyprUS

4

String是不可變的源。附加一個字符串只能生成一個新的字符串。

StringBuilder是可變的。追加到StringBuilder是就地操作,如添加到ArrayList。

+0

您好Slaks,我知道。我想知道字符串生成器如何執行該操作。 – javaMan

2

StringBuffer就像StringBuilder一樣分配一個char數組,將它複製到你追加的字符串中。它只在字符數超過數組大小時創建新對象,在這種情況下,它會重新分配並複製數組。

1

StringBuilder被保持的char秒的緩衝液中char[]並將其轉換爲一個StringtoString被調用。

3

這不會編譯。

String S= "orange"; 
S.append("apple"); 

如果你

final String S= "orange"; 
final S2 = S + "apple"; 

,因爲它是在編譯時優化,以兩個String文字這不會創建任何對象。

StringBuilder s = new StringBuilder("Orange"); 
s.append("apple"); 

這就造成了兩個對象StringBuilder和它包裝的char[]。如果您使用

String s2 = s.toString(); 

這會創建另外兩個對象。

如果這樣做

String S= "orange"; 
S2 = S + "apple"; 

這是相同

String S2 = new StringBuilder("orange").append("apple").toString(); 

其產生2 + 2 = 4個對象。

0

如其他人所述,StringBuffer是可變的,它通過使用char數組來實現。 StringBuffer中的操作是就地操作。

的詳細信息可以是可從下面的鏈接 http://www.concentric.net/~ttwang/tech/jfastbuf.htm

它示出了使用char陣列簡單的StringBuffer實現。

2
String s = "orange"; 
s.append("apple"); 

這是不正確的,因爲append方法的字符串不是可用的:

-1
****String s1="Azad"; ----One object will create in String cons. pool 

System.out.println(s1);--output--Azad 

s1=s1.concat("Raja"); Two object will create 1-Raja,2-AzadRaja and address of AzadRaja Store in reference s1 and cancel ref.of Azad object 

System.out.println(s1); --output AzadRaja**** 
+0

您的答案非常難以閱讀。它是否添加了已接受答案中尚未包含的任何有用信息? –

1

TL; DR:簡單地說,每一個字符串連接表達使用+字符導致新的String對象與初始字符串的內容被複制到新的。 StringBuffer擁有一個內部結構,只有在需要時纔會擴展,將字符添加到其中。

嘿,但很多人使用+字符串連接!

那麼,我們/他們不應該。該調整大小,道理,但很少,如果在大小調整應用的算法是有效的,並且只有一個String對象創建一次toString() -

在內存使用方面,您是爲了保持字符使用數組中StringBuffer被稱爲,比在每個+級聯上創建新的String對象好得多。

在時間複雜度方面,字符從_chars只複製一次新的字符串(O(n)時間複雜度),這一般就是必須比使用+操作,對每個操作導致一個新的副本字符串連接好將字符轉換爲新對象,從而導致O(1 + 2 + .... + n) = O(n^2)操作。

我應該自己實施一個嗎?

這對你來說在鍛鍊方面是有好處的,但現代語言提供本地StringBuffer實現來在生產代碼中使用它。

在四個簡單的步驟:

  1. 創建MyCustomStringBuilder類在內部(私人)成立的陣列(讓我們將其命名爲_chars)固定的初始大小的字符。這個數組將持有 的字符串字符。
  2. 添加一個擴展方法,將會增加_chars一次的大小 控制字符串字符長度超過其長度。 (你在做什麼,在內部實現簡單版本的 ArrayList)。
  3. 當使用stringBufferInstance.append(String s)方法時,將 個字符添加到_chars,如果需要增加其大小。
  4. 在你toString()方法實現,你可以簡單地創建一個string using the array

    public String toString() { 
        return new String(_chars); 
    } 
    
相關問題