В чем разница между текстом и новой строкой (текст)? - PullRequest
179 голосов
/ 16 июня 2010

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

String s = "text";

String s = new String("text");

Ответы [ 11 ]

175 голосов
/ 16 июня 2010

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

Ссылки

Смежные вопросы

108 голосов
/ 08 мая 2014

String литералы войдут в Пул строковых констант .

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

enter image description here


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

String str1 = new String("java5");

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

String str2 = "java5"

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

String str3 = new String(str2);

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

String str4 = "java5";

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

Всего объектов: Heap - 2, Pool - 1

Дополнительная информация о сообществе Oracle

15 голосов
/ 16 июня 2010

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

String s = "text";

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

String s = new String("text");

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

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

8 голосов

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.

Байт-код

Также полезно взглянуть на реализацию байт-кода в 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: создан новый экземпляр строки (с * 1074)* в качестве аргумента)
  • 35: a и c сравниваются как обычные объекты с if_acmpne

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

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

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

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

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

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

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

1 голос
/ 15 января 2019

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

String obj1 = "abc";
String obj2 = "abc";

"obj1" и "obj2" будут указывать на один и тот же строковый литерал, а пул строкового литерала будет иметь только один литерал "abc".

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

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

1 голос
/ 07 июля 2015

@ Braj: я думаю, что вы упомянули об обратном.Пожалуйста, исправьте меня, если я ошибаюсь

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

String str1 = new String ("java5")

   Pool- "java5" (1 Object)

   Heap - str1 => "java5" (1 Object)

String str2 = "java5"

  pool- str2 => "java5" (1 Object)

  heap - str1 => "java5" (1 Object)

String str3 = новая строка (str2)

  pool- str2 => "java5" (1 Object)

  heap- str1 => "java5", str3 => "java5" (2 Objects)

String str4 = "java5"

  pool - str2 => str4 => "java5" (1 Object)

  heap - str1 => "java5", str3 => "java5" (2 Objects)
1 голос
/ 16 июня 2010

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

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

Таким образом, new String () всегда будет создавать новый экземпляр.

1 голос
/ 16 июня 2010

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

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

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

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

0 голосов
/ 27 января 2019

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

String string1 = "Hello";

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

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

String string2 = "Hello";

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

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

String string = new String("Hello");

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

0 голосов
/ 15 сентября 2015
String str = new String("hello")

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

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

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

String str = "world";

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...