Java字符串生成器附加计算

Java字符串生成器附加计算,java,concatenation,stringbuilder,Java,Concatenation,Stringbuilder,当我使用StringBuilder的append时,实际的复制何时发生?当我调用append时,还是当我将生成器作为字符串计算时 我这样问是因为在我的应用程序中有很多log.debugstrA+strB+。。。我希望避免对生产代码中的串联进行求值。我知道java优化了+ops并将它们转换为字符串生成器的附加,但我不知道在附加函数中是否真的发生了连接。StringBuilder包含一个字符数组。append向该数组添加字符。显式或隐式调用stringBuilderInstance.toString

当我使用StringBuilder的append时,实际的复制何时发生?当我调用append时,还是当我将生成器作为字符串计算时


我这样问是因为在我的应用程序中有很多log.debugstrA+strB+。。。我希望避免对生产代码中的串联进行求值。我知道java优化了+ops并将它们转换为字符串生成器的附加,但我不知道在附加函数中是否真的发生了连接。

StringBuilder包含一个字符数组。append向该数组添加字符。显式或隐式调用stringBuilderInstance.toString后,将根据stringbuilder的内容创建一个新的字符串实例。

在stringbuilder中,当您附加时,这意味着您正在连接字符串。否,额外对象是在内部创建的。这只是附加!使用.toString将StringBuilder转换为字符串时,内容会从StringBuilder复制到字符串对象

两者都有。当您附加到StringBuilder时,您正在将字符复制到其内部字符数组中。将生成器转换为字符串时,将内容复制到字符串实例的内部数组中。

StringBuilder扩展了AbstractStringBuilder,其中有几个附加方法:

public AbstractStringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}

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


public AbstractStringBuilder append(StringBuffer sb) {
    if (sb == null)
        return appendNull();
    int len = sb.length();
    ensureCapacityInternal(count + len);
    sb.getChars(0, len, value, count);
    count += len;
    return this;
}

AbstractStringBuilder append(AbstractStringBuilder asb) {
    if (asb == null)
        return appendNull();
    int len = asb.length();
    ensureCapacityInternal(count + len);
    asb.getChars(0, len, value, count);
    count += len;
    return this;
}

@Override
public AbstractStringBuilder append(CharSequence s) {
    if (s == null)
        return appendNull();
    if (s instanceof String)
        return this.append((String)s);
    if (s instanceof AbstractStringBuilder)
        return this.append((AbstractStringBuilder)s);

    return this.append(s, 0, s.length());
}
它使用char[]值;声明以声明所有字符的存储。 追加新字符串时,它会检查值数组的当前长度,如有必要,它会调用ensureCapacityInternal:

并在必要时调用expandCapacity:

/**
 * This implements the expansion semantics of ensureCapacity with no
 * size check or synchronization.
 */
void expandCapacity(int minimumCapacity) {
    int newCapacity = value.length * 2 + 2;
    if (newCapacity - minimumCapacity < 0)
        newCapacity = minimumCapacity;
    if (newCapacity < 0) {
        if (minimumCapacity < 0) // overflow
            throw new OutOfMemoryError();
        newCapacity = Integer.MAX_VALUE;
    }
    value = Arrays.copyOf(value, newCapacity);
}

结论:追加新数据时正在调用复制,字符值数组的容量不足以存储此新数据。

您应该看看slf4j,它有采用字符串格式的日志方法和要替换的对象。连接发生在append函数中。
/**
 * This implements the expansion semantics of ensureCapacity with no
 * size check or synchronization.
 */
void expandCapacity(int minimumCapacity) {
    int newCapacity = value.length * 2 + 2;
    if (newCapacity - minimumCapacity < 0)
        newCapacity = minimumCapacity;
    if (newCapacity < 0) {
        if (minimumCapacity < 0) // overflow
            throw new OutOfMemoryError();
        newCapacity = Integer.MAX_VALUE;
    }
    value = Arrays.copyOf(value, newCapacity);
}