StringBuffer 如何在不创建两个对象的情况下实现 append 函数? [英] How is StringBuffer implementing append function without creating two objects?

查看:34
本文介绍了StringBuffer 如何在不创建两个对象的情况下实现 append 函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我是这样想的.

String s = "orange";s.append("苹果");

这里创建了两个对象.

但是

StringBuilder s = new StringBuilder("Orange");s.append("苹果");

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

Java 是如何进行这个操作的?

解决方案

首先你的问题有问题:

String s = "orange";s.append("苹果");

<块引用>

这里创建了两个对象

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

StringBuilder s = new StringBuilder("Orange");s.append("苹果");

<块引用>

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

我不知道你从哪里得到的,在这里你创建了一个 StringBuilder 对象,一个橙色"字符串,一个苹果"字符串,总共 3 个对象,如果我们溢出 StringBuilder 缓冲区,则创建 4 个.(我把数组的创建算作对象的创建)

<小时>

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

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

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

StringBuilder 扩展 AbstractStringBuilder,您将在其中找到以下代码:

/*** 该值用于字符存储.*/字符值[];

由于不是所有的数组都会在给定的时间被使用,另一个重要的变量是长度:

/*** 计数是使用的字符数.*/整数计数;

append 的重载有很多,但最有趣的一个是:

public AbstractStringBuilder append(String str) {if (str == null) str = "null";//如果为空,将逐字附加空"int len = str.length();//获取字符串长度如果(len == 0)返回这个;//如果它是零,我就完成了int newCount = 计数 + len;//暂定的新长度if (newCount > value.length)//新的长度是否合适?扩展容量(新计数);//哎呀,不,调整我的数组大小str.getChars(0, len, value, count);//现在它将适合,复制字符计数 = 新计数;//更新计数返回这个;//返回对自己的引用以允许链接}

<块引用>

String.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 将此字符串中的字符复制到目标字符数组中.

所以,append方法非常简单,唯一需要发现的就是expandCapacity,这里是:

void expandCapacity(int minimumCapacity) {//获取当前长度加一并加倍int newCapacity = (value.length + 1) * 2;if (newCapacity < 0) {//如果我们有一个整数溢出newCapacity = Integer.MAX_VALUE;//只使用最大的正整数} else if (minimumCapacity > newCapacity) {//够了吗?//如果加倍还不够,使用计算的实际长度newCapacity = 最小容量;}//复制新数组中的旧值value = Arrays.copyOf(value, newCapacity);}

<块引用>

Arrays.copyOf(char[] original, int newLength) 复制指定的数组,用空字符截断或填充(如有必要),使副本具有指定的长度.

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

It was an interview question. I was asked to implement the StringBuffer append function. I saw the code after the interview. But I cannot understand how the operation is done with creation of a single object.

I am thinking like this.

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

Here two objects are created.

But

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

Now here only one object is created.

How is Java doing this operation?

解决方案

First there is a problem with your question:

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

here two objects are created

Correct, two Objects are created, the String "orange" and the String "apple", inside the StringBuffer/StringBuilder no Objects will be created if we don't overflow the buffer. So those lines of code create 2 or 3 objects.

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

Now here only one object is created

I don't know where you get that, here you create one StringBuilder Object, one "Orange" String, one "apple" String, for a total of 3 Objects, or 4 if we overflow the StringBuilder buffer. (I count the array creation as object creation).


I read your question as, how can StringBuilder do the append without creating a new Object (when the buffer is not overflown)?

You should look at StringBuilder, since it's the non thread safe implementation. The code is interesting and easy to read. I've added the inline comments.

As internal structure there is a char array, not a String. It is initially built with length 16 and will be increased every time the capacity is exceeded. If the Strings to append fit within the char array, there is no need to create new Objects.

StringBuilder extends AbstractStringBuilder, where you'll find the following code:

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

Since not all the array will be used at a given time, another important variable is the length:

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

There are many overloading of append, but the most interesting one is the following:

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) Copies characters from this string into the destination character array.

So, the append method is quite simple, the only magic left to discover is the expandCapacity, here it is:

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) Copies the specified array, truncating or padding with null characters (if necessary) so the copy has the specified length.

In our case, padding, since we're expanding the length.

这篇关于StringBuffer 如何在不创建两个对象的情况下实现 append 函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆