Подсчет объектов String, созданных кодом Java
Сколько объектов String создается следующим кодом?
String x = new String("xyz");
String y = "abc";
x = x + y;
Я посетил многие веб-сайты, где некоторые говорят, что эта строка кода создает 3 объекта, а некоторые говорят, что она создает 4. Я просто хотел узнать, сколько объектов создано после выполнения этой строки кода.
Ответы
Ответ 1
К концу прогона будут четыре объекта String
:
- A
String
, который соответствует интернированному литералу "xyz"
- Его копия, созданная
new String("xyz")
- A
String
, который соответствует интернированному литералу "abc"
- A
String
, который соответствует конкатенации "xyz" + "abc"
Реальный вопрос заключается в том, что некоторые или все эти объекты относятся к вашей программе. Можно разумно утверждать, что ваш код составляет всего два или четыре элемента String
. Несмотря на то, что существует всего четыре объекта String
, объекты 1 и 3 могут не обязательно создаваться вашим кодом, потому что они находятся в постоянном пуле, поэтому они создаются вне прямого управления вашим кодом.
Ответ 2
Этот ответ должен исправить ошибочное представление, которое вызывает некоторые другие ответы:
Например:
Компилятор может заменить x + y константой ( "xyzabc" ). @Binkan Salaryman
... и объект String 4 [строка, соответствующая конкатенации] может быть вычислен компилятором и также превращена в интернированную константу. @dasblinkenlight
Это неверно. В JLS указано следующее:
15.18.1. Оператор конкатенации строк +
....
Объект String только что создан (§12.5), если выражение не является постоянным выражением (§15.28).
Чтобы квалифицироваться как константное выражение, имена переменных в выражении должны быть:
Простые имена (§6.5.6.1), которые относятся к постоянным переменным (§4.12.4).
где "постоянная переменная" определяется как:
Постоянная переменная является конечной переменной примитивного типа или типа String, которая инициализируется константным выражением (§15.28).
В этом примере ни x
, либо y
не являются final
, поэтому они не являются постоянными переменными. И даже если они были final
, y
по-прежнему не будет постоянной переменной из-за использования оператора new
в его инициализации.
Короче говоря, компилятору Java не разрешено использовать постоянную константу "xyzabc"
в результате выражения конкатенации.
Если в конце я добавил следующий оператор:
System.out.println(x == "xyzabc");
он всегда будет печатать false
... при условии, что компилятор соответствует спецификации языка Java.
Ответ 3
Взгляните на декомпилированный класс, и вы увидите все:) Ответ должен быть:
- две строки (
"xyz"
и "abc"
) - это только ссылки на позиции в постоянном пуле, поэтому они не созданы вашим кодом.
- создается одна строка напрямую (
new String("xyz")
)
-
конкатенация строк оптимизирована компилятором и изменена на StringBuilder, поэтому последняя строка создается косвенно
public java.lang.String method();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=3, locals=3, args_size=1
0: new #2 // class java/lang/String
3: dup
4: ldc #3 // String xyz
6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: ldc #5 // String abc
12: astore_2
13: new #6 // class java/lang/StringBuilder
16: dup
17: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
20: aload_1
21: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: aload_2
25: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_1
32: aload_1
33: areturn
Ответ 4
Ответ 4.
Как вы использовали ключевое слово new
, Java создаст новый объект String в обычной (не пул) памяти, а x
будет ссылаться на него. В дополнение к этому, буквальный "xyz" будет помещен в пул строк, который снова является другим строковым объектом.
Итак, 4 строковых объекта:
- "xyz" (в памяти без пула)
- "xyz" (в памяти пула)
- "abc" (в памяти пула)
- "xyzabc" (в памяти без пула)
Если ваш код был таким:
String x = "xyz";
String y = "abc";
x = x + y;
тогда ответ будет 3.
Примечание. Строка №4 находится в памяти без пула, так как строковые литералы и строки, полученные путем вычисления постоянных выражений (см. JLS §15.28), являются единственными строками, которые неявно интернированы.
Источник: SCJP Sun Certified Programmer для Java 6 (Страница: 434, глава 6)
Ответ 5
Если вы хотите протестировать экземпляры, запустите этот фрагмент кода и посмотрите на вывод:
import static java.lang.System.identityHashCode;
public class Program {
public static void main(String... args) {
String x = new String("xyz");
String y = "abc";
String z = x + y;
System.out.printf("x: %d | %d\n", identityHashCode(x), identityHashCode(x.intern()));
System.out.printf("y: %d | %d\n", identityHashCode(y), identityHashCode(y.intern()));
System.out.printf("z: %d | %d\n", identityHashCode(z), identityHashCode(z.intern()));
}
}
У меня есть следующий вывод, используя jdk1.7.0_67:
x: 414853995 | 1719175803
y: 1405489012 | 1405489012
z: 1881191331 | 1881191331
Это всего 4 String
экземпляров...
Ответ 6
new String("xyz")
наверняка создаст новый экземпляр. "abc"
и "xyz"
сохраняются в пуле констант класса, x = x + y
создает StringBuilder
под капотом и поэтому создает new String
, поэтому количество строк здесь 4.
Компилятор может заменить x + y
константой ("xyzabc"
).
Ответ 7
Я бы сказал 4, потому что:
Вот как:
String x = new String("xyz"); // 2 objects created: the variable and the constant
String y = "abc"; // 1 object created: the variable
x = x + y; // 1 object created: the one by the StringBuilder class
Ответ 8
Причина, по которой вы видите разные ответы на вопрос, (частично), что она неоднозначна.
"Сколько объектов String создается следующим кодом?"
Неопределенность выражается в фразе "созданной следующим кодом":
-
Он спрашивает о количестве объектов String, созданных (просто) при выполнении кода?
-
Или... спрашивает о количестве объектов String, которые должны существовать во время выполнения кода?
Можно утверждать, что код неявно создает объекты String, которые соответствуют литералам, а не когда они запускаются, но когда они загружаются. Однако эти объекты могут использоваться совместно с другим кодом, который использует те же литералы. (И если вы выглядите достаточно сложно, возможно, что во время процесса загрузки класса создаются другие строковые объекты, содержащие одни и те же строки символов.)
Другая причина, по которой вы видите разные ответы, состоит в том, что не совсем понятно, сколько строк создается. В разных спецификациях утверждается, что в определенные моменты будут созданы новые объекты String, но есть "комната для изгибания" относительно того, могут ли быть созданы промежуточные объекты String.
Например, JLS утверждает, что new
всегда создает новый объект и что оператор конкатенации строк создает новый объект, за исключением определенных явно определенных случаев (см. мой другой ответ). Однако спецификации не запрещают создание других строк за кадром.
Но в этом случае, если предположить, что мы используем современный Hotspot JVM, то:
- 2 строковых объекта существуют (для строковых литералов) до начала запуска кода и
- При выполнении кода создаются 2 новых строковых объекта (оператором
new
и +
).
Существование/создание этих 4 строк гарантируется JLS.
Ответ 9
Ответ 4
String x = new String("xyz");//First Object
String y = "abc";//Second Object
x = x + y;//Third, fourth Object
Ответ 10
Иногда лучше указывать байт-код
Изучение кода с помощью JAVAP
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
0: new #16 // class java/lang/String
3: dup
4: ldc #18 // String xyz
6: invokespecial #20 // Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: ldc #23 // String abc
12: astore_2
13: new #25 // class java/lang/StringBuilder
16: dup
17: aload_1
18: invokestatic #27 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
21: invokespecial #31 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
24: aload_2
25: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/St
ringBuilder;
28: invokevirtual #36 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_1
32: return
LineNumberTable:
line 6: 0
line 7: 10
line 8: 13
line 9: 32
LocalVariableTable:
Start Length Slot Name Signature
0 33 0 args [Ljava/lang/String;
10 23 1 x Ljava/lang/String;
13 20 2 y Ljava/lang/String;
}
Теперь, как видно, код
At `0: new` Creates a new String Object
At `3:dup` ; make an extra reference to the new instance
At `4:ldc #18` as seen literal "xyz" has been placed in the pool (one string Object)
At `6: invokespecial;` ; now call an instance initialization method with parameter and creates a object in nonpool memory.
At `9: astore_1` Stores the above reference in local variable 1(i.e x)
Итак, к этому времени у нас есть два объекта String
At `10:ldc #23` as seen literal "abc" has been placed in the pool (third string )
At `12: astore_2` Stores the above reference in local variable (i.e y)
Итак, к этому времени у нас есть три объекта String
28: invokevirtual #36 // Method java/lang/StringBuilder.toString:
()Ljava/lang/String;;(fourth String Object is Created)
Итак, у нас есть всего четыре объекта String в этом коде.
Поскольку я новичок в программировании и начал его, изучая только несколько месяцев назад, напомните мне, если я где-то ошибся и что это правильная версия. Спасибо:)
Ответ 11
Line 1:String x = new String("xyz");
Line 2:String y = "abc";
Line 3:x = x + y;
Строки неизменяемы, поэтому, если необходимо изменить существующую строковую переменную, тогда для назначения будет создан новый объект. Строка 1, строка 2 являются строковыми объектами, где, поскольку строка 3 является модификацией существующей строковой переменной, необходимо выполнить новое распределение, чтобы добавить x + y. Поэтому он должен создать создает 3 объекта.
Ответ 12
1.объекты, созданные в области кучи "xyz"//созданные с помощью String x и xyzabc//созданные с помощью x + y (объединение)
2.объекты, созданные в scp (пул строковых констант) "xyz"//созданы для будущих целей, которые недоступны для сборки мусора, а "abc"//созданы литералом 'String y'
поэтому общее количество созданных объектов в этом случае составляет 4
Ответ 13
Ответ 5
- XYZ в памяти без пула
- XYZ в памяти пула без ссылки
- abc в пуле памяти со ссылкой
- xyz все еще находится в памяти без пула, ссылка изменена на xyzabc в памяти без пула
- xyzabc в пуле памяти без ссылки