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

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

我在想这个。

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

这里创建了两个对象。

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

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

Java如何进行此操作?

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

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

这里创建了两个对象

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

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

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

我不知道你在哪里得到它,在这里你创建一个StringBuilder对象,一个“橙色”字符串,一个“苹果”字符串,总共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)将此字符串中的字符复制到目标字符数组中。

所以,append方法非常简单,唯一可以发现的魔法就是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)复制指定的数组,截断或填充空字符(如有必要),使副本具有指定的长度。

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

来源是你的朋友卢克!

这是AbstractStringBuilder的源代码

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

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

这不编译。

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

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

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

这是不正确的,因为在String中没有append方法:

StringBuilderchar[]保存char的缓冲区,并在调用toString时将它们转换为String

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

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

好吧,我们/他们不应该。

就内存使用而言,你在StringBuffer中使用一个数组来保存字符 – resize,真相,但是如果在resize时应用的算法很有效,并且只调用一次创建一个toString() String对象,则很少,比在每个+连接上创建一个新的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()方法实现中,您只需使用数组创建一个字符串 :

     public String toString() { return new String(_chars); } 

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

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

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

 ****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****