Емкость StringBuilder()

Я заметил, что метод capacity возвращает емкость StringBuilder без какой-либо логики... иногда его значение равно длине строки, иногда больше...

есть ли уравнение, чтобы узнать, в чем его логика?


person xdevel2000    schedule 06.07.2010    source источник
comment
Почему тебя волнует capacity? Он автоматически растет, чтобы вместить все необходимое. Вы можете поиграть с ним, чтобы улучшить производительность, но он все равно будет асимптотически линейным.   -  person polygenelubricants    schedule 06.07.2010
comment
На экзамене OCA есть вопросы о capacity и length, поэтому для некоторых людей этот вопрос имеет большое значение.   -  person Igor Soudakevitch    schedule 12.05.2016


Ответы (8)


Когда вы добавляете к StringBuilder, происходит следующая логика:

if (newCount > value.length) {
    expandCapacity(newCount);
}

где newCount — необходимое количество символов, а value.length — текущий размер буфера.

expandCapacity просто увеличивает размер подложки char[]

Метод ensureCapacity() является общедоступным способом вызова expandCapacity(), и его документы говорят:

Гарантирует, что емкость по крайней мере равна указанному минимуму. Если текущая емкость меньше аргумента, то выделяется новый внутренний массив с большей емкостью. Новая емкость больше:

  • Аргумент минимальной емкости.
  • Вдвое больше прежней емкости, плюс 2.

Если аргумент MinimumCapacity неположителен, этот метод не выполняет никаких действий и просто возвращает значение.

person Bozho    schedule 06.07.2010
comment
да, но если у меня есть: StringBuilder str = new StringBuilder(); // емкость 16 стр.append(1111111111111111111); вместимость 32 длина 19 По уравнению почему вместимость не 16 * 2 + 2 = 34?? - person xdevel2000; 06.07.2010
comment
Обратите внимание, что это деталь реализации, документ не гарантирует, что методы добавления вызывают ensureCapacity. - person Marcono1234; 02.11.2019

Я попытаюсь объяснить это на каком-нибудь примере.

public class StringBuilderDemo {
     public static void main(String[] args) {
         StringBuilder sb = new StringBuilder();
         System.out.println(sb.length());
         System.out.println(sb.capacity());
     }
}

length() - длина последовательности символов в построителе, так как этот построитель строк не содержит никакого содержимого, его длина будет равна 0.

capacity() - количество выделенных символов. Когда вы пытаетесь построить построитель строк с пустым содержимым, по умолчанию он принимает размер инициализации как длина + 16, что составляет 0 + 16. поэтому емкость вернет 16 здесь.

Примечание. Емкость, возвращаемая методом capacity(), всегда больше или равна длине (обычно больше) и будет автоматически расширяться по мере необходимости, чтобы учесть дополнения к построителю строк.

Логика функции емкости:

  1. Если вы не инициализируете stringbuilder с каким-либо содержимым, емкость по умолчанию будет принята за 16 символов.
  2. Если вы инициализируете stringbuilder с любым содержимым, то емкость будет равна длине содержимого + 16.
  3. Когда вы добавляете новый контент в объект stringbuilder, если текущей емкости недостаточно для принятия нового значения, она будет увеличиваться на (предыдущая емкость массива+1)*2.

Этот анализ взят из фактический код StringBuilder.java

person user1923551    schedule 10.12.2013

Эта функция делает что-то другое, чем вы ожидаете - она ​​дает вам максимальное количество символов, которое может хранить эта память экземпляра StringBuilder в это время.

Построитель строк должен читать

person InsertNickHere    schedule 06.07.2010

Вот логика: если вы определяете новый экземпляр класса StringBuilder без конструктора, например new StringBuilder();, емкость по умолчанию равна 16. Конструктор может быть либо int, либо String. Для конструктора String емкость по умолчанию рассчитывается следующим образом.

int newCapacity = string.length() + 16;

Для конструктора int вместимость рассчитывается так

int newCapacity = intSpecified + 16;

Если к StringBuilder добавляется новый String, а новая длина String больше текущей емкости, то емкость рассчитывается следующим образом:

int newCapacity = (oldCapacity + 1) * 2;
person Ayokunle Paul    schedule 16.03.2018

РЕДАКТИРОВАТЬ: Извинения - ниже приведена информация о .NET StringBuilder, которая не имеет строгого отношения к исходному вопросу.

http://johnnycoder.com/blog/2009/01/05/stringbuilder-required-capacity-algorithm/

StringBuilder выделяет пространство для подстрок, которые вы можете добавить к нему (так же, как List создает пространство для массива, который он обертывает). Если вам нужна фактическая длина строки, используйте StringBuilder.Length.

person Alex Humphrey    schedule 06.07.2010
comment
Эта статья о C#, не так ли? - person Andreas Dolk; 06.07.2010
comment
Ага. Формула похожа на Java, но не совсем такая же. - person Catchwa; 06.07.2010
comment
Мои извинения - я видел StringBuilder и предположил .NET. - person Alex Humphrey; 06.07.2010

Из API:

У каждого строителя струн есть емкость. Пока длина последовательности символов, содержащейся в построителе строк, не превышает емкости, нет необходимости выделять новый внутренний буфер. Если внутренний буфер переполняется, он автоматически увеличивается.

Всякий раз, когда вы что-то добавляете, выполняется проверка, чтобы убедиться, что обновленный StringBuilder не превысит свою емкость, и если это произойдет, внутреннее хранилище StringBuilder будет изменено:

int len = str.length();
int newCount = count + len;
if (newCount > value.length)
  expandCapacity(newCount);

Когда к нему добавляются данные, которые превышают его емкость, его размер изменяется в соответствии со следующей формулой:

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);
}

Дополнительные сведения см. в файле src.zip, который поставляется вместе с JDK. (Приведенные выше фрагменты взяты из 1.6 JDK)

person Catchwa    schedule 06.07.2010
comment
Интересно! Может быть, они убрали это как оптимизацию? - person Catchwa; 06.07.2010
comment
Может быть, однако в документацию jdk 7, которая еще не обновлена! - person xdevel2000; 06.07.2010

Вы можете зайти внутрь кода JDK и посмотреть, как он работает, он основан на массиве символов: new char[capacity], он похож на то, как работает ArrayList (Когда использовать LinkedList вместо ArrayList?). Оба используют массивы для «аппаратной эффективности», хитрость заключается в том, чтобы выделить большой кусок памяти и работать в нем до тех пор, пока у вас не закончится память и вам не понадобится следующий большой кусок для продолжения (расширения/роста).

person Christophe Roussy    schedule 09.12.2015

в Яве 1.8

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;
}

private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,
                newCapacity(minimumCapacity));
    }
}

Например :

StringBuilder str = new StringBuilder();  
System.out.println(str.capacity()); //16

str.append("123456789012345"); 
System.out.println(str.capacity()); //16

str.append("12345678901234567890"); 
System.out.println(str.capacity()); // 15 + 20 = 35
person HenryChuang    schedule 02.11.2019