Я заметил, что метод capacity
возвращает емкость StringBuilder
без какой-либо логики... иногда его значение равно длине строки, иногда больше...
есть ли уравнение, чтобы узнать, в чем его логика?
Я заметил, что метод capacity
возвращает емкость StringBuilder
без какой-либо логики... иногда его значение равно длине строки, иногда больше...
есть ли уравнение, чтобы узнать, в чем его логика?
Когда вы добавляете к StringBuilder
, происходит следующая логика:
if (newCount > value.length) {
expandCapacity(newCount);
}
где newCount
— необходимое количество символов, а value.length
— текущий размер буфера.
expandCapacity
просто увеличивает размер подложки char[]
Метод ensureCapacity()
является общедоступным способом вызова expandCapacity()
, и его документы говорят:
Гарантирует, что емкость по крайней мере равна указанному минимуму. Если текущая емкость меньше аргумента, то выделяется новый внутренний массив с большей емкостью. Новая емкость больше:
- Аргумент минимальной емкости.
- Вдвое больше прежней емкости, плюс 2.
Если аргумент MinimumCapacity неположителен, этот метод не выполняет никаких действий и просто возвращает значение.
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(), всегда больше или равна длине (обычно больше) и будет автоматически расширяться по мере необходимости, чтобы учесть дополнения к построителю строк.
Логика функции емкости:
Этот анализ взят из фактический код StringBuilder.java
Эта функция делает что-то другое, чем вы ожидаете - она дает вам максимальное количество символов, которое может хранить эта память экземпляра StringBuilder в это время.
Построитель строк должен читать
Вот логика: если вы определяете новый экземпляр класса 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;
РЕДАКТИРОВАТЬ: Извинения - ниже приведена информация о .NET StringBuilder, которая не имеет строгого отношения к исходному вопросу.
http://johnnycoder.com/blog/2009/01/05/stringbuilder-required-capacity-algorithm/
StringBuilder выделяет пространство для подстрок, которые вы можете добавить к нему (так же, как List создает пространство для массива, который он обертывает). Если вам нужна фактическая длина строки, используйте StringBuilder.Length.
Из 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)
Вы можете зайти внутрь кода JDK и посмотреть, как он работает, он основан на массиве символов: new char[capacity]
, он похож на то, как работает ArrayList
(Когда использовать LinkedList вместо ArrayList?). Оба используют массивы для «аппаратной эффективности», хитрость заключается в том, чтобы выделить большой кусок памяти и работать в нем до тех пор, пока у вас не закончится память и вам не понадобится следующий большой кусок для продолжения (расширения/роста).
в Яве 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
capacity
? Он автоматически растет, чтобы вместить все необходимое. Вы можете поиграть с ним, чтобы улучшить производительность, но он все равно будет асимптотически линейным. - person polygenelubricants   schedule 06.07.2010capacity
иlength
, поэтому для некоторых людей этот вопрос имеет большое значение. - person Igor Soudakevitch   schedule 12.05.2016