Как StringBuffer реализует функцию append без создания двух объектов?

Это был вопрос. Меня попросили реализовать StringBuffer функция append. Я видел код После интервью. Но я не могу понять, как выполняется операция с созданием одного объекта.

Я думаю так.

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

здесь создаются два объекта.

но

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

Теперь здесь создается только один объект.

как Java делает эту операцию?

10 ответов


сначала возникает проблема с вашим вопросом:

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

здесь создаются два объекта

правильно, создаются два объекта, строка " оранжевый "и строка" яблоко", внутри StringBuffer/StringBuilder никакие объекты не будут созданы, если мы не переполняем буфер. Таким образом, эти строки кода создают 2 или 3 объекта.

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

теперь здесь создается только один объект

Я не знаю где вы это получите, здесь вы создаете один объект StringBuilder, одну" оранжевую "строку, одну" яблочную " строку для в общей сложности 3 объектов или 4, Если мы переполняем буфер StringBuilder. (Я считаю создание массива как создание объекта).


я прочитал Ваш вопрос, как StringBuilder может добавить без создания нового объекта (когда буфер не переполнен)?

вы должны посмотреть StringBuilder, так как это не потокобезопасная реализация. Код интересно и легко читается. Я добавил встроенные комментарии.

в качестве внутренней структуры существует массив символов, а не строка. Она изначально построена с длиной 16 и будет увеличиваться каждый раз, когда объем. Если строки для добавления подходят в массив char, нет необходимости создавать новые объекты.

StringBuilder выходит AbstractStringBuilder, где вы найдете следующий код:

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

так как не весь массив будет использоваться на в данный момент времени другой важной переменной является длина:

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

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

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
}

строку.метод getchars(int srcBegin, int srcEnd, char[] dst, int dstBegin) копирует символы из этой строки в целевой массив символов.

Итак, метод добавления довольно прост, единственная магия, оставшаяся для обнаружения, - это expandCapacity, вот это есть:

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

массивы.copyOf(char [] original, int newLength) копирует указанный массив, усекая или дополняя нулевыми символами (при необходимости), чтобы копия имела указанную длину.

в нашем случае, обивка, так как мы расширяем длину.


на источник - твой друг, Люк!

вот источник AbstractStringBuilder


String незыблем. Добавление строки может генерировать только новую строку.

StringBuilder изменчиво. Добавление к StringBuilder в месте операции, как добавить в ArrayList.


это не компилируется.

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

если у вас

final String S= "orange";
final S2 = S + "apple";

это не создает никаких объектов, поскольку он оптимизирован во время компиляции до двух строковых литералов.

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

это создает два объекта StringBuilder и char[] она оборачивается. Если вы используете

String s2 = s.toString();

это создает еще два объекта.

если у вас

String S= "orange";
S2 = S + "apple";

это то же самое, что

String S2 = new StringBuilder("orange").append("apple").toString();

который создает 2 + 2 = 4 объекта.


StringBuffer, как StringBuilder выделяет массив символов, в который он копирует строки, которые вы добавляете. Он создает новые объекты только тогда, когда количество символов превышает размер массива, в этом случае он перераспределяет и копирует массив.


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

это неправильно, потому что метод добавления недоступен в строке:


StringBuilder держит буфер charС char[] и преобразование их в String, когда toString называется.


tl; dr: простыми словами, каждая конкатенация строк выражение С помощью + символ приводит к новому String объект с содержимым исходных строк, копируемых в новую. StringBuffer имеет внутреннюю структуру, которая расширяется только при необходимости, что символы добавляются к нему.

Эй, но многие люди используют + конкатенация строк!

Ну, мы/они не должен.

С точки зрения использования памяти, вы используете массив в StringBuffer чтобы удерживать символы-это изменяет размер, правда, но редко, если алгоритм, применяемый при изменении размера, эффективен, и только один String объект, который создается однажды toString() называется, гораздо лучше, чем создание новой


как другие описывали, StringBuffer является изменяемым и реализуется с помощью char массив. Операции в StringBuffer в месте операции.

еще информация может быть доступна по следующей ссылке http://www.concentric.net / ~ttwang/tech/jfastbuf.htm

он показывает простые реализации StringBuffer с помощью char массив.


****String s1="Azad"; ----One object will create in String cons. pool

System.out.println(s1);--output--Azad

s1=s1.concat("Raja");  Two object will create 1-Raja,2-AzadRaja and address of AzadRaja Store in reference s1 and cancel ref.of Azad object 

System.out.println(s1);  --output AzadRaja****