Подтвердить что ты не робот

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

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

Я так думаю.

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

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

Но

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

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

Как работает эта операция Java?

4b9b3361

Ответ 1

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

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

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

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

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

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

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


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

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

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

StringBuilder extends 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 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
}

String.getChars (int srcBegin, int srcEnd, char [] dst, int dstBegin) Копирует символы из этой строки в пункт назначения массив символов.

Итак, метод append довольно прост, единственное, что осталось открыть, - это 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); 
}

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

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

Ответ 3

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

StringBuilder является изменяемым. Добавление к StringBuilder - это операция на месте, например добавление в ArrayList.

Ответ 4

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

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 объекта.

Ответ 5

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

Ответ 6

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

Это неверно, потому что метод append недоступен в String:

Ответ 7

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

Ответ 8

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

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

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

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

В терминах временной сложности символы копируются только один раз из _chars в новую строку (O(n) временная сложность), которая в общем случае должна быть лучше, чем конкатенация строк с помощью оператора +, на котором каждая операция приводит к новой копии символов для нового объекта, что приводит к операциям O(1 + 2 + .... + n) = O(n^2).

Должен ли я реализовать его самостоятельно?

Это было бы хорошо для вас с точки зрения упражнений, но современные языки предоставляют собственные реализации StringBuffer для использования в производственном коде.

В четырех простых шагах:

  • Создайте класс MyCustomStringBuilder, который внутри (в частном порядке) содержит массив (пусть он называет его _chars) символов фиксированного начального размера. Этот массив будет содержать строковые символы.
  • Добавьте метод расширения, который будет увеличивать размер _chars один раз длина символа удерживающей строки превышает ее длину. (Что ты практически, реализует простую версию ArrayList внутренне).
  • При использовании метода stringBufferInstance.append(String s) добавьте символов до _chars, при необходимости увеличивая его размер.
  • В вашей реализации метода toString() вы можете просто создать строку используя массив:

    public String toString() {
        return new String(_chars);
    }
    

Ответ 9

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

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

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

Ответ 10

****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****