StringBuffer如何在不创建两个对象的情况下实现追加功能?

时间:2011-11-04 15:05:38

标签: java string stringbuilder

这是一个面试问题。我被要求实施StringBuffer追加功能。我在采访后看到了代码。但我无法理解如何通过创建单个对象来完成操作。

我在想这个。

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

这里创建了两个对象。

但是

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

现在这里只创建了一个对象。

Java如何执行此操作?

10 个答案:

答案 0 :(得分:49)

首先,您的问题存在问题:

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

这里创建了两个对象

正确,在StringBuffer / StringBuilder中创建了两个对象,字符串“orange”和字符串“apple”,如果我们不溢出缓冲区,则不会创建对象。所以这些代码行创建了2个或3个对象。

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

现在这里只创建了一个对象

我不知道你在哪里得到它,在这里你创建一个StringBuilder对象,一个“Orange”字符串,一个“apple”字符串,总共3个对象,如果我们溢出StringBuilder缓冲区则为4。 (我将数组创建视为对象创建)。


我读了你的问题,StringBuilder如何在不创建新Object的情况下执行追加(当缓冲区没有溢出时)?

您应该查看StringBuilder,因为它是非线程安全的实现。代码很有趣,易于阅读。我添加了内联评论。

作为内部结构,有一个char数组,而不是String。它最初构建为长度为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 [] original,int newLength)复制指定的数组,截断或填充空字符(如有必要),使副本具有指定的长度。

在我们的例子中,填充,因为我们正在扩展长度。

答案 1 :(得分:9)

source是你的朋友,卢克!

以下是AbstractStringBuilder

的来源

答案 2 :(得分:4)

String是不可变的。附加字符串只能生成新字符串。

StringBuilder是可变的。附加到StringBuilder是一个就地操作,就像添加到ArrayList一样。

答案 3 :(得分:3)

这不会编译。

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

如果你这样做

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

这不会创建任何对象,因为它在编译时被优化为两个字符串文字。

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个对象。

答案 4 :(得分:2)

与StringBuilder一样,StringBuffer会分配一个char数组,它会复制你追加的字符串。它只在字符数超过数组大小时才创建新对象,在这种情况下,它会重新分配和复制数组。

答案 5 :(得分:2)

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

这是不正确的,因为追加方法在字符串中不可用:

答案 6 :(得分:1)

StringBuilderchar中持有char[]个缓冲区,并在调用String时将其转换为toString

答案 7 :(得分:1)

tl; dr:简单来说,使用+字符的每个字符串连接表达式会导致带有内容的新String对象将初始字符串复制到新字符串中。 StringBuffer拥有一个内部结构,只有在需要时才会扩展,并将字符附加到其上。

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

嗯,我们/他们不应该。

就内存使用而言,你在StringBuffer中使用一个数组来保存字符 - 调整大小,真相,但很少,如果在调整大小时应用的算法是有效的,并且只有一个{{1}调用String后创建的对象,比在每个toString()连接上创建新的String对象要好得多。

就时间复杂度而言,字符只会从+复制一次到新字符串(_chars时间复杂度),这通常必须比使用O(n)的字符串连接更好运算符,每个操作都会将字符的新副本导向新对象,从而导致+操作。

我应该自己实施吗?

在练习方面对你有好处,但现代语言提供了原生的O(1 + 2 + .... + n) = O(n^2)实现,可以在生产代码中使用它。

通过四个简单的步骤:

  1. 创建一个StringBuffer类,在内部(私有)保存一个固定初始大小的字符数组(我们将其命名为MyCustomStringBuilder)。这个数组将成立 字符串字符。
  2. 添加一个扩展方法,该方法会增加_chars一次的大小 保持字符串字符长度超过其长度。 (你呢 实际上正在实施一个简单的版本 内部_chars
  3. 使用ArrayList方法时,请添加 字符到stringBufferInstance.append(String s),如果需要增加其大小。
  4. _chars方法实施中,您只需创建一个string using the array

    toString()

答案 8 :(得分:0)

正如其他人所描述的那样,StringBuffer是可变的,它是通过使用char数组实现的。 StringBuffer中的操作是就地操作。

可以从以下链接获得更多信息 http://www.concentric.net/~ttwang/tech/jfastbuf.htm

它显示了使用char数组的简单StringBuffer实现。

答案 9 :(得分:-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****