2011-11-04 55 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); 
    } 
    
相关问题