Java StringBuffer如何在不创建两个对象的情况下实现append函数?

Java StringBuffer如何在不创建两个对象的情况下实现append函数?,java,string,stringbuilder,Java,String,Stringbuilder,这是一个面试问题。我被要求实现StringBufferappend函数。面试后我看到了密码。但我无法理解如何通过创建单个对象来完成操作 我是这样想的 String s = "orange"; s.append("apple"); 这里创建了两个对象 但是 现在这里只创建了一个对象 Java是如何执行此操作的?这是您的朋友,Luke 以下是字符串的源代码是不可变的。追加字符串只能生成新字符串 StringBuilder是可变的。附加到StringBuilder是一个就地操作,就像添加到Array

这是一个面试问题。我被要求实现
StringBuffer
append函数。面试后我看到了密码。但我无法理解如何通过创建单个对象来完成操作

我是这样想的

String s = "orange";
s.append("apple");
这里创建了两个对象

但是

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

Java是如何执行此操作的?

这是您的朋友,Luke


以下是字符串的源代码

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


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

StringBuffer,就像StringBuilder分配一个字符数组,它将附加的字符串复制到该数组中。仅当字符数超过数组大小时,它才会创建新对象,在这种情况下,它会重新分配和复制数组。

StringBuilder
char[]中保留
char
s的缓冲区
并在调用
toString
时将它们转换为
字符串。

首先,您的问题有一个问题:

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如何在不创建新对象的情况下进行追加(当缓冲区没有溢出时)

您应该看看
StringBuilder
,因为它是非线程安全的实现。代码有趣且易于阅读。我已经添加了内联注释

作为内部结构,有一个字符数组,而不是字符串。它最初的长度为16,每次超过容量时都会增加。如果要附加的字符串适合char数组,则无需创建新对象


StringBuilder
extends,您可以在其中找到以下代码:

/**
 * The value is used for character storage.
 */
char value[];
由于在给定时间不会使用所有数组,另一个重要变量是长度:

/**  
 * The count is the number of characters used.
 */
int count;
append有很多重载,但最有趣的是:

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
}
(int-srcbegen,int-srcEnd,char[]dst,int-dstbegen)将此字符串中的字符复制到目标字符数组中

因此,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); 
}
void expandCapacity(int最小容量){
//获取当前长度加一并加倍
int newCapacity=(value.length+1)*2;
if(newCapacity<0){//如果我们有一个整数溢出
newCapacity=Integer.MAX_VALUE;//只需使用最大正整数
}否则如果(minimumCapacity>newCapacity){//,是否足够?
//如果加倍还不够,请使用计算的实际长度
新容量=最小容量;
}
//将旧值复制到新数组中
value=Arrays.copyOf(value,newCapacity);
}
(char[]original,int newLength)复制指定的数组,截断或填充空字符(如有必要),使副本具有指定的长度

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

这不会编译

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

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

更多信息可从以下链接获得

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

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

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

tl;dr:简单地说,每个使用
+
字符的字符串连接表达式都会导致一个新的
字符串
对象,并将初始字符串的内容复制到新对象中
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****
嘿,但是很多人使用
+
字符串连接

嗯,我们/他们不应该

在内存使用方面,您正在使用
StringBuffer
中的数组来保存字符-这会调整大小,但如果在调整大小时应用的算法是有效的,则很少会这样做,并且只调用一个
String
对象,该对象创建一次
toString()
,比在每个
+
串联上创建新的
字符串
对象要好得多

就时间复杂度而言,字符仅从
\u chars
复制一次到新字符串(
O(n)
时间复杂度),这通常必须优于使用
+
运算符的字符串串联,在该运算符上,每次操作都会将字符的新副本复制到新对象,从而导致
O(1+2+..+n)=O(n^2)
操作

我应该自己实施一个吗?

这在练习方面对您有好处,但现代语言提供了本机
StringBuffer
实现,以便在生产代码中使用它

四个sim卡
****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****
public String toString() {
    return new String(_chars);
}