Страницы

Поиск по вопросам

четверг, 2 января 2020 г.

Количество созданий новых строк в куче

#java #строки #heap


Один из вопросов в OCA7 выглядит так:

public class Mounds {
public static void main(String[] args) {
    StringBuilder sb = new StringBuilder();
    String s = new String();
    for (int i = 0; i < 1000; i++) {
        s += " " + i;
        sb.append(s);
    }
    // done with loop
} }



  Если сборщик мусора не будет работать во время исполнения кода, сколько примерно
объектов будет существовать в памяти, когда цикл завершится?
  
  A. Меньше 10;
  
  B. Примерно 1000;
  
  C. Примерно 2000;
  
  D. Примерно 3000;
  
  E. Примерно 4000.


Со StringBuilder все понятно: он mutable, как создался, так один и остался.
А поскольку String является immutable классом, каждый раз создается новый объект.
Сперва я подумал, что правильный ответ - B, 1000 объектов по количеству итераций. Но
потом присмотрелся к телу цикла:

s += " " + i;


Здесь мы видим, что каждый раз к пробелу (который создается в пуле строк лишь единожды)
каждый раз конкатенируется значения i, которое, соответственно, каждый раз создает
новую строку со значением i, то есть "0", "1", "2" и так далее, которые затем превращаются
в новые строки "0", "0 1", "0 1 2" и так далее. И подумал, что правильный ответ - C,
2000 объектов - по одному на каждую новую строку s и каждую новую строку значения i.

Однако в книжке приводится, что правильный ответ - B. Объясните, пожалуйста, в чем
я ошибся?
    


Ответы

Ответ 1



Оператор += можно расписать так s = s + " " + i; Поэтому на каждой итерации будет создаваться по одной строке и присваиваться переменной s. Т.е. Java сразу сложит все в одну строку вместо того, чтобы создавать её по частям. Если бы мы вынесли " " + i в отдельную переменную, а потом добавили к s, тогда бы был вариант, о котором Вы подумали.

Ответ 2



Давайте посмотрим чем будет заниматься JVM при выполнении этого задания. Декомпиляция примера дает такой результат: public class Mounds { public Mounds() { // тут конструктор по умолчанию } public static void main(String[] args) { StringBuilder sb = new StringBuilder(); String s = new String(); for(Object i = 0; i < 1000; ++i) { sb.append((String)i); // а тут сюрприз! } } } Хотя классическое описание операции объединения строк с помощью оператора + предполагает следующую конструкцию: s = new StringBuilder(s).append(" ").append((String)i)).toString() в которой будет создано аж три объекта: сам new StringBuilder() новая строка (String)i и new String()в результате работы последнего toString(), мы видим что компилятор не стал размениваться на подобные мелочи и использовал имеющийся StringBuilder чтобы сократить количество объектов и операций к мнимому. Т.о. каждый цикл создается только новый объект String в момент преобразования числа к строке, и ответ 1000 похож на правду.

Комментариев нет:

Отправить комментарий