Сколько объектов String будет создано при объединении нескольких строк?

Меня спросили в интервью о количестве объектов, которые будут созданы по данной проблеме:

String str1 = "First";
String str2 = "Second";
String str3 = "Third";
String str4 = str1 + str2 + str3;

Я ответил, что в строке будет создано 6 объектов бассейн.

3 будет для каждой из трех переменных.
1 будет для str1 + str2 (скажем, str).
1 будет для str2 + str3.
1 будет для str + str3 (str = str1 + str2).

Правильный ли ответ я дал? Если нет, каков правильный ответ?

36
задан Dukeling 24 August 2019 в 10:52
поделиться

7 ответов

Любой ответ на Ваш вопрос будет зависеть от реализации JVM и версии Java, в настоящее время используясь. Я думаю, что это - неблагоразумный вопрос спросить в интервью.

Java 8

На моей машине, с Java 1.8.0_201, Ваш отрывок приводит к этому байт-коду

L0
 LINENUMBER 13 L0
 LDC "First"
 ASTORE 1
L1
 LINENUMBER 14 L1
 LDC "Second"
 ASTORE 2
L2
 LINENUMBER 15 L2
 LDC "Third"
 ASTORE 3
L3
 LINENUMBER 16 L3
 NEW java/lang/StringBuilder
 DUP
 INVOKESPECIAL java/lang/StringBuilder.<init> ()V
 ALOAD 1
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 ALOAD 2
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 ALOAD 3
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
 ASTORE 4

, который доказывает, что 5 объектов создаются (3 String, литералы*, 1 StringBuilder , 1 динамично произвели String экземпляр [1 115] StringBuilder#toString ).

Java 12

На моей машине, с Java 12.0.2, байт-код

// identical to the bytecode above
L3
 LINENUMBER 16 L3
 ALOAD 1
 ALOAD 2
 ALOAD 3
 INVOKEDYNAMIC makeConcatWithConstants(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; [
  // handle kind 0x6 : INVOKESTATIC
  java/lang/invoke/StringConcatFactory.makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
  // arguments:
  "\u0001\u0001\u0001"
 ]
 ASTORE 4

который волшебно изменения "корректный ответ" на [1 142] 4 объекта , так как нет никакого промежуточного звена StringBuilder включено.

<час>

*Let роют немного глубже.

12.5. Создание Новых Экземпляров класса

А новый экземпляр класса может быть неявно создано в следующих ситуациях:

  • Загрузка класса или интерфейса, который содержит строковый литерал ( В§3.10.5 ) может создать новый Строковый объект представить литерал. (Это не произойдет, если строка, обозначающая ту же последовательность кодовых точек Unicode, была ранее интернирована.)

, Другими словами, когда Вы запускаете приложение, в Строковом пуле уже существуют объекты. Вы едва знаете то, что они и куда они происходят из (если Вы не сканируете все загруженные классы для всех литералов, они содержат).

java.lang.String класс будет, несомненно, загружен как существенный класс JVM, означая, что все его литералы будут созданы и помещены в пул.

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

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence,
               Constable, ConstantDesc {
    ...
    public String repeat(int count) {
        // ... 
        if (Integer.MAX_VALUE / count < len) {
            throw new OutOfMemoryError("Repeating " + len + " bytes String " + count +
                    " times will produce a String exceeding maximum size.");
        }
    }
    ...
}

Они там действительно.

<глоток> Как интересная находка, фильтрация этой ИДЕИ имеет побочный эффект: подстроки, которые я искал, были добавлены к пулу также. Размер пула, увеличенный одним ("bytes String" был добавлен) после того, как я подал заявку this.contains("bytes String").

, Где это оставляет нас?

Мы понятия не имеем, был ли "First" создан и интернирован, прежде чем мы будем звонить String str1 = "First";, таким образом, мы не можем заявить твердо, что строка создает новый экземпляр.

31
ответ дан 27 November 2019 в 05:50
поделиться

С данной информацией нельзя определенно ответить на вопрос. Как указан в JLS, В§15.18.1 :

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

Это означает, что ответ зависит, по крайней мере, от конкретного используемого компилятора Java.

я думаю лучшее, которое мы можем сделать, дают интервал как ответ:

  • умный компилятор может быть в состоянии вывести, что str1 к str3 никогда не используются и сворачивают конкатенацию во время компиляции, такой, что только один String - объект создается (тот, на который ссылаются str4)
  • максимальное разумное количество String, созданная с должна быть 5: один каждый для str1 к str3, один для tmp = str1 + str2 и один для str4 = tmp + str3.

, Таким образом... мой ответ был бы "чем-то между один - пять String - объекты". Относительно общего количества объектов, созданных только для этой операции... Я не знаю. Это может также зависеть, как точно, например, StringBuffer реализован.

Как в стороне: Интересно, какова причина позади задавания таких вопросов. Обычно, не нужно заботиться о тех деталях.

18
ответ дан 27 November 2019 в 05:50
поделиться

Java 8, вероятно, создаст 5 объектов:

  • 3 для этих 3 литералов
  • 1 StringBuilder
  • 1 для связанного String

С вещами Java 9 изменился , хотя и String конкатенация не использует StringBuilder больше.

7
ответ дан 27 November 2019 в 05:50
поделиться

Это должно быть 5:

  • три для этих трех литералов (присвоенный str1, str2 и str3)

  • один для str1 + str2

  • один для (result from the previous operation) + str3 (присвоенный str4)

4
ответ дан 27 November 2019 в 05:50
поделиться

4 строковых объекта будут созданы в пуле строковой константы. 3 для литералов и 1 с конкатенацией.

, если мы используем

String s1 = new String("one")

, это создаст два, возражают один в постоянном пуле и один в памяти "кучи".

, если мы определяем:

String s1 = "one";
String s2 = new String("one");

это создаст два, возражают один в постоянном пуле и один в памяти "кучи".

2
ответ дан 27 November 2019 в 05:50
поделиться

Совместимая реализация Java может связать строки любое количество путей, во время выполнения или во время компиляции, нуждаясь в любом количестве объектов периода выполнения, включая нулевые объекты, если это обнаруживает, что результат не нужен во время выполнения.

3
ответ дан 27 November 2019 в 05:50
поделиться

Операция конкатенации не создает те много Строковых объектов. Это создает StringBuilder и затем добавляет строки. Таким образом, может быть 5 объектов, 3 (переменные) + 1 (сурьма) + 1 (Сцепленная строка).

1
ответ дан 27 November 2019 в 05:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: