【问题标题】:Java StringBuffer append allocationJava StringBuffer 追加分配
【发布时间】:2011-04-28 09:02:34
【问题描述】:

在java中使用StringBuffer时,我想知道append函数在需要重新分配空间时是如何实现的。

例如,如果我追加一个比当前分配的空间长的字符串,它在方法的细节中是如何管理的?

【问题讨论】:

  • StringBuffer 不是字符串。当您使用方法时,它只需要将内容变为字符串,例如toString,这会导致(新)字符串。虽然这个问题在“但它在下面如何”类型中很有趣......

标签: java stringbuffer


【解决方案1】:

Apache Harmony 实现依赖于AbstractStringBuilder 中的方法来管理添加/删除(StringBuffer 扩展AbstractStringBuilder)。

AbstractStringBuilder 保留一个字符缓冲区(即chars 的数组)来保存当前的“字符串”。当将任何对象的下一个字符串表示附加到此缓冲区时,它会检查缓冲区是否包含足够的空间,如果没有足够的空间,它会分配一个新的字符缓冲区,复制旧缓冲区,然后将新字符串添加到该缓冲区。我们可以从enlargeBuffer 的内部收集到这一点:

private void enlargeBuffer(int min) {
    int newSize = ((value.length >> 1) + value.length) + 2;
    char[] newData = new char[min > newSize ? min : newSize];
    System.arraycopy(value, 0, newData, 0, count);
    value = newData;
    shared = false;
 }

...当value(保存字符缓冲区的私有成员)的容量将被超出时,在任何附加方法中都会调用此方法:

final void append0(char chars[]) {
    int newSize = count + chars.length;
    if (newSize > value.length) {
         enlargeBuffer(newSize);
     }
     System.arraycopy(chars, 0, value, count, chars.length);
     count = newSize;
}

标准的 OpenJDK 实现非常相似。同样,StringBuffer 依赖于AbstractStringBuilder

void expandCapacity(int minimumCapacity) {
    int newCapacity = (value.length + 1) * 2;
    if (newCapacity < 0) {
        newCapacity = Integer.MAX_VALUE;
    } else if (minimumCapacity > newCapacity) {
        newCapacity = minimumCapacity;
    }
    value = Arrays.copyOf(value, newCapacity);
}

注意Arrays.copyOf 复制字符数组value 用空字符填充它以获得总大小newCapacity,这基本上相当于Harmony 方法中的new char[...] 调用。同样,当没有足够的空间添加下一个字符串段时,将调用expandCapacity 方法:

public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
    int len = str.length();
    if (len == 0) return this;
    int newCount = count + len;
    if (newCount > value.length)
         expandCapacity(newCount);
    str.getChars(0, len, value, count);
    count = newCount;
    return this;
}

【讨论】:

    【解决方案2】:

    源代码包含在 JDK 下载中。只需查找 src.zip 文件(我的位于 Program Files (x86)\Java\jdk1.6.0_01\src.zip 中)。解压后直接到java/lang,可以查看StringBuffer.java、StringBuilder.java、AbstractStringBuilder.java。

    在这个实现中,看起来像 AbstractStringBuilder 中的“expandCapacity”计算容量并执行 Arrays.copyOf() 来扩展缓冲区。有趣的是,首先检查

    void expandCapacity(int minimumCapacity) {
        int newCapacity = (value.length + 1) * 2;
        if (newCapacity < 0) {
            newCapacity = Integer.MAX_VALUE;
        } else if (minimumCapacity > newCapacity) {
            newCapacity = minimumCapacity;
        }
        value = Arrays.copyOf(value, newCapacity);
    }
    

    【讨论】:

    • I.E - 容量不断翻倍。这使 Appends 的摊销成本保持不变(以可能有一半的缓冲区空间为空为代价)。
    猜你喜欢
    • 1970-01-01
    • 2014-10-23
    • 2015-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-05
    • 2017-12-05
    相关资源
    最近更新 更多