В чем разница между "текстом" и новой строкой ( "текст" )?

В чем разница между этими двумя следующими утверждениями?

String s = "text";

String s = new String("text");

Ответ 1

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). Однако нужно повторить, что это очень странно и редко является намерением.

Ссылки

Связанные проблемы

Ответ 2

Строковые литералы войдут в String Constant Pool.

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

enter image description here


Создание объектов по строкам:

String str1 = new String("java5");

Используя строковый литерал "java5" в конструкторе, новое строковое значение сохраняется в пуле строковых констант. Используя новый оператор, в куче создается новый строковый объект с "java5" в качестве значения.

String str2 = "java5"

Ссылка "str2" указана на уже сохраненное значение в пуле строковых констант

String str3 = new String(str2);

Новый строковый объект создается в куче с тем же значением, что и ссылка на "str2",

String str4 = "java5";

Ссылка "str4" указана на уже сохраненное значение в пуле константных строк

Всего объектов: Куча - 2, Бассейн - 1

Дальнейшее чтение сообщества Oracle

Ответ 3

Один создает строку в String Constant Pool

String s = "text";

другой создает строку в пуле констант ("text") и другую строку в обычном пространстве кучи (s). Обе строки будут иметь то же значение, что и "текст".

String s = new String("text");

s затем теряется (имеет право на GC), если позже не используется.

Строковые литералы, с другой стороны, используются повторно. Если вы используете "text" в нескольких местах вашего класса, это фактически будет одна и только одна строка (т.е. Несколько ссылок на одну и ту же строку в пуле).

Ответ 4

JLS

Концепция называется "интернированием" 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

JVMs

JVMS 7 5.1 говорит:

Строковый литерал является ссылкой на экземпляр класса 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.

Bytecode

Поучительно также взглянуть на реализацию байт-кода на 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

Представление постоянных строк довольно банально на байт-коде:

  • у него есть специальная структура CONSTANT_String_info, в отличие от обычных объектов (например, new String)
  • struct указывает на CONSTANT_Utf8_info Structure, которая содержит данные. Это единственные необходимые данные для представления строки.

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

Я сделал аналогичные тесты для полей и:

  • static final String s = "abc" указывает на таблицу констант через ConstantValue Attribute
  • Нефинансовые поля не имеют этого атрибута, но могут быть инициализированы с помощью ldc

Заключение: существует прямая поддержка байт-кода для пула строк, и представление памяти является эффективным.

Бонус: сравните это с Целочисленным пулом, который не имеет прямой поддержки байт-кода (т.е. нет CONSTANT_String_info).

Ответ 5

Подумайте, что "bla" является волшебным factory как Strings.createString("bla") (псевдо). factory содержит пул всех строк, которые все еще созданы таким образом.

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

Если нет, он создает внутренний объект строки внутри, сохраняет его в пуле и затем возвращает его. Таким образом, когда в следующий раз запрашивается одно и то же строковое значение, он возвращает тот же экземпляр.

Вручное создание new String("") переопределяет это поведение путем обхода пула строковых литералов. Поэтому равенство всегда следует проверять с помощью equals(), который сравнивает последовательность символов вместо равенства ссылки на объект.

Ответ 6

Один простой способ понять разницу ниже: -

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() всегда будет создавать новый экземпляр.

Ответ 7

@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)

Ответ 8

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

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" будет проверен на наличие в пуле строк и будет создан, так как он не существует в вышеуказанный случай.

Ответ 9

Хотя он выглядит одинаково с точки зрения программистов, он имеет большое влияние на производительность. Вы бы хотели использовать первую форму почти всегда.

Ответ 10

String str = new String("hello")

Он проверит, содержит ли пул константных строк String "hello"? Если присутствует, то он не будет добавлять запись в пул строк String. Если нет, то он добавит запись в пул строк String.

Объект будет создан в области памяти кучи и str опорных точек к объекту, созданному в ячейке памяти кучи.

если вы хотите, чтобы str ссылалась на объект точки, содержащийся в пуле строк String, нужно явно вызвать str.intern();

String str = "world";

Он проверит, содержит ли пул константных строк String "hello"? Если присутствует, то он не будет добавлять запись в пул строк String. Если нет, то он добавит запись в пул констант String.

В приведенном выше случае str указывает на String "world", присутствующий в пуле констант.

Ответ 11

Когда вы храните строку как

String string1 = "Hello";

непосредственно, затем JVM создает объект String с заданной ценой в течение отдельного блока памяти, называемого постоянным пулом String.

И всякий раз, когда мы имеем тенденцию пытаться создать другую строку как

String string2 = "Hello";

JVM проверяет, существует ли какой-либо объект String с постоянной ценой в пуле констант String, если это так, вместо создания нового объекта JVM назначает ссылку на существующий объект новой переменной.

И когда мы храним String как

String string = new String("Hello");

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