В чем разница между этими двумя следующими утверждениями?
String s = "text";
String s = new String("text");
В чем разница между этими двумя следующими утверждениями?
String s = "text";
String s = new String("text");
new String("text");
явно создает новый и ссылочно отдельный экземпляр объекта String; String s = "text"; может повторно использовать экземпляр из пула константных строк , если он доступен.
Вы очень редко захотите использовать конструктор new String(anotherString). Из API:
String(String original): Инициализирует вновь созданный объектString, чтобы он представлял ту же последовательность символов, что и аргумент; Другими словами, вновь созданная строка является копией строки аргумента. Если явная копия оригинала не нужна, использование этого конструктора необязательно, поскольку строки неизменяемы.
Изучите следующий фрагмент:
String s1 = "foobar";
String s2 = "foobar";
System.out.println(s1 == s2); // true
s2 = new String("foobar");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
== по двум ссылочным типам - это сравнение ссылочной идентичности. Два объекта equals не обязательно ==. Обычно неверно использовать == для ссылочных типов; большую часть времени equals нужно использовать вместо этого.
Тем не менее, если по какой-либо причине вам нужно создать две строки equals, но не ==, вы можете использовать конструктор new String(anotherString). Однако нужно повторить, что это очень странно и редко является намерением.
Строковые литералы войдут в String Constant Pool.
Следующий снимок может помочь вам понять его визуально, чтобы запомнить его на более длительное время.

Создание объектов по строкам:
String str1 = new String("java5");
Используя строковый литерал "java5" в конструкторе, новое строковое значение сохраняется в пуле строковых констант. Используя новый оператор, в куче создается новый строковый объект с "java5" в качестве значения.
String str2 = "java5"
Ссылка "str2" указана на уже сохраненное значение в пуле строковых констант
String str3 = new String(str2);
Новый строковый объект создается в куче с тем же значением, что и ссылка на "str2",
String str4 = "java5";
Ссылка "str4" указана на уже сохраненное значение в пуле константных строк
Всего объектов: Куча - 2, Бассейн - 1
Один создает строку в String Constant Pool
String s = "text";
другой создает строку в пуле констант ("text") и другую строку в обычном пространстве кучи (s). Обе строки будут иметь то же значение, что и "текст".
String s = new String("text");
s затем теряется (имеет право на GC), если позже не используется.
Строковые литералы, с другой стороны, используются повторно. Если вы используете "text" в нескольких местах вашего класса, это фактически будет одна и только одна строка (т.е. Несколько ссылок на одну и ту же строку в пуле).
Концепция называется "интернированием" JLS.
Соответствующий переход от JLS 7 3.10.5:
Кроме того, строковый литерал всегда ссылается на тот же экземпляр класса String. Это связано с тем, что строковые литералы, или, в более общем смысле, строки, которые являются значениями константных выражений (§15.28), "интернированы", чтобы обмениваться уникальными экземплярами, используя метод String.intern.
Пример 3.10.5-1. Строковые литералы
Программа, состоящая из единицы компиляции (§7.3):
package testPackage; class Test { public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.print((hello == "Hello") + " "); System.out.print((Other.hello == hello) + " "); System.out.print((other.Other.hello == hello) + " "); System.out.print((hello == ("Hel"+"lo")) + " "); System.out.print((hello == ("Hel"+lo)) + " "); System.out.println(hello == ("Hel"+lo).intern()); } } class Other { static String hello = "Hello"; }и блок компиляции:
package other; public class Other { public static String hello = "Hello"; }выводит результат:
true true true true false true
Строковый литерал является ссылкой на экземпляр класса String и выводится из структуры CONSTANT_String_info (§4.4.3) в двоичном представлении класса или интерфейса. Структура CONSTANT_String_info дает последовательность кодовых точек Unicode, составляющих строковый литерал.
Язык программирования Java требует, чтобы идентичные строковые литералы (то есть литералы, содержащие одну и ту же последовательность кодовых точек) должны относиться к одному экземпляру класса String (JLS §3.10.5). Кроме того, если метод String.intern вызывается в любой строке, результатом является ссылка на тот же экземпляр класса, который будет возвращен, если эта строка появилась как литерал. Таким образом, следующее выражение должно иметь значение true:
("a" + "b" + "c").intern() == "abc"Чтобы получить строковый литерал, виртуальная машина Java проверяет последовательность кодовых точек, заданных структурой CONSTANT_String_info.
Если метод String.intern ранее был вызван в экземпляр класса String, содержащий последовательность кодовых точек Unicode, идентичную последовательности, заданной структурой CONSTANT_String_info, тогда результат строкового литерала является ссылкой на этот тот же экземпляр класса String.
В противном случае создается новый экземпляр класса String, содержащий последовательность кодовых точек Unicode, заданную структурой CONSTANT_String_info; ссылка на этот экземпляр класса является результатом строкового литерала. Наконец, вызывается метод intern нового экземпляра String.
Поучительно также взглянуть на реализацию байт-кода на OpenJDK 7.
Если мы декомпилируем:
public class StringPool {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
String c = new String("abc");
System.out.println(a);
System.out.println(b);
System.out.println(a == c);
}
}
мы имеем в постоянном пуле:
#2 = String #32 // abc
[...]
#32 = Utf8 abc
и main:
0: ldc #2 // String abc
2: astore_1
3: ldc #2 // String abc
5: astore_2
6: new #3 // class java/lang/String
9: dup
10: ldc #2 // String abc
12: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
15: astore_3
16: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
26: aload_2
27: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
30: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_1
34: aload_3
35: if_acmpne 42
38: iconst_1
39: goto 43
42: iconst_0
43: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V
Обратите внимание, как:
0 и 3: загружается одна и та же константа ldc #2 (литералы)12: создается новый экземпляр строки (с аргументом #2)35: a и c сравниваются как обычные объекты с if_acmpneПредставление постоянных строк довольно банально на байт-коде:
new String)и приведенная выше ссылка JVMS, похоже, говорит, что всякий раз, когда указатель Utf8 одинаковый, то идентичные экземпляры загружаются ldc.
Я сделал аналогичные тесты для полей и:
static final String s = "abc" указывает на таблицу констант через ConstantValue AttributeldcЗаключение: существует прямая поддержка байт-кода для пула строк, и представление памяти является эффективным.
Бонус: сравните это с Целочисленным пулом, который не имеет прямой поддержки байт-кода (т.е. нет CONSTANT_String_info).
Подумайте, что "bla" является волшебным factory как Strings.createString("bla") (псевдо). factory содержит пул всех строк, которые все еще созданы таким образом.
Если он вызывается, он проверяет, есть ли уже строка в пуле с этим значением. Если true, он возвращает этот строковый объект, следовательно, полученные таким образом строки действительно являются одним и тем же объектом.
Если нет, он создает внутренний объект строки внутри, сохраняет его в пуле и затем возвращает его. Таким образом, когда в следующий раз запрашивается одно и то же строковое значение, он возвращает тот же экземпляр.
Вручное создание new String("") переопределяет это поведение путем обхода пула строковых литералов. Поэтому равенство всегда следует проверять с помощью equals(), который сравнивает последовательность символов вместо равенства ссылки на объект.
Один простой способ понять разницу ниже: -
String s ="abc";
String s1= "abc";
String s2=new String("abc");
if(s==s1){
System.out.println("s==s1 is true");
}else{
System.out.println("s==s1 is false");
}
if(s==s2){
System.out.println("s==s2 is true");
}else{
System.out.println("s==s2 is false");
}
вывод
s==s1 is true
s==s2 is false
Таким образом, новый String() всегда будет создавать новый экземпляр.
@Braj: Я думаю, что ты упомянул об этом наоборот. Пожалуйста, поправьте меня, если я ошибаюсь
Создание объектов по строкам:
String str1 = new String ( "java5" )
Pool- "java5" (1 Object)
Heap - str1 => "java5" (1 Object)
Строка str2 = "java5"
pool- str2 => "java5" (1 Object)
heap - str1 => "java5" (1 Object)
String str3 = new String (str2)
pool- str2 => "java5" (1 Object)
heap- str1 => "java5", str3 => "java5" (2 Objects)
Строка str4 = "java5"
pool - str2 => str4 => "java5" (1 Object)
heap - str1 => "java5", str3 => "java5" (2 Objects)
Любой строковый литерал создается внутри пула строковых литералов, и пул не допускает дублирования. Таким образом, если два или более строковых объекта инициализируются одним и тем же литеральным значением, тогда все объекты будут указывать на один и тот же литерал.
String obj1 = "abc";
String obj2 = "abc";
"obj1" и "obj2" будут указывать на один и тот же строковый литерал, а пул строкового литерала будет иметь только один литерал "abc".
Когда мы создаем объект класса String, используя ключевое слово new, созданная таким образом строка сохраняется в памяти кучи. Любой строковый литерал, переданный в качестве параметра конструктору класса String, однако, сохраняется в пуле строк. Если мы создадим несколько объектов, используя одно и то же значение с оператором new, новый объект будет создаваться в куче каждый раз, потому что этого нового оператора следует избегать.
String obj1 = new String("abc");
String obj2 = new String("abc");
"obj1" и "obj2" будут указывать на два разных объекта в куче, а пул строкового литерала будет иметь только один литерал "abc".
Также следует отметить, что в отношении поведения строк следует отметить, что любое новое присваивание или конкатенация, выполняемые со строкой, создают новый объект в памяти.
String str1 = "abc";
String str2 = "abc" + "def";
str1 = "xyz";
str2 = str1 + "ghi";
Теперь в приведенном выше случае:
Строка 1: литерал "abc" хранится в пуле строк.
Строка 2: литерал "abcdef" сохраняется в пуле строк.
Строка 3: новый литерал "xyz" сохраняется в пуле строк, и "str1" начинает указывать на этот литерал.
Строка 4: поскольку значение генерируется путем добавления к другой переменной, результат сохраняется в памяти кучи, а добавляемый литерал "ghi" будет проверен на наличие в пуле строк и будет создан, так как он не существует в вышеуказанный случай.
Хотя он выглядит одинаково с точки зрения программистов, он имеет большое влияние на производительность. Вы бы хотели использовать первую форму почти всегда.
String str = new String("hello")
Он проверит, содержит ли пул константных строк String "hello"? Если присутствует, то он не будет добавлять запись в пул строк String. Если нет, то он добавит запись в пул строк String.
Объект будет создан в области памяти кучи и str опорных точек к объекту, созданному в ячейке памяти кучи.
если вы хотите, чтобы str ссылалась на объект точки, содержащийся в пуле строк String, нужно явно вызвать str.intern();
String str = "world";
Он проверит, содержит ли пул константных строк String "hello"? Если присутствует, то он не будет добавлять запись в пул строк String. Если нет, то он добавит запись в пул констант String.
В приведенном выше случае str указывает на String "world", присутствующий в пуле констант.
Когда вы храните строку как
String string1 = "Hello";
непосредственно, затем JVM создает объект String с заданной ценой в течение отдельного блока памяти, называемого постоянным пулом String.
И всякий раз, когда мы имеем тенденцию пытаться создать другую строку как
String string2 = "Hello";
JVM проверяет, существует ли какой-либо объект String с постоянной ценой в пуле констант String, если это так, вместо создания нового объекта JVM назначает ссылку на существующий объект новой переменной.
И когда мы храним String как
String string = new String("Hello");
используя ключевое слово new, создается совершенно новый объект с заданной ценой независимо от содержимого пула констант String.