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

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

String s = "text";

String s = new String("text");

13 ответов

Решение

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" в конструкторе, новое строковое значение сохраняется в пуле строковых констант. Используя оператор new, в куче создается новый строковый объект со значением "java5".

String str2 = "java5"

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

String str3 = new String(str2);

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

String str4 = "java5";

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

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

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

Создается строка в пуле строковых констант

String s = "text";

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

String s = new String("text");

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

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

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)
  • структура указывает на структуру CONSTANT_Utf8_info, которая содержит данные. Это единственные необходимые данные для представления строки.

и приведенная выше цитата JVMS, кажется, говорит, что всякий раз, когда Utf8, на который указывают ldc,

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

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

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

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

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

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

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

Когда мы создаем объект класса String с использованием нового ключевого слова, созданная таким образом строка сохраняется в памяти кучи. Любой строковый литерал, переданный в качестве параметра конструктору класса 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" будет проверен на наличие в пуле строк и будет создан, так как он не существует в вышеуказанный случай.

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

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

String str1 = новая строка ("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)

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

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

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

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

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

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

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

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

String string1 = "Hello";

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

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

String string2 = "Hello";

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

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

String string = new String("Hello");

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

Когда вы используете что-то вродеnew String("Hello World")инструмент анализа кода SpotBugs жалуется напроблемы с производительностью.

Описание этого вопроса показывает уважениеnewиconstant string

Используяjava.lang.String(String)конструктор тратит память, потому что созданный таким образом объект будет функционально неотличим от строки, переданной в качестве параметра. Просто используйте аргумент String напрямую.
Тип и шаблон ошибки: Dm - DM_STRING_CTOR

Извините за поздний ответ, но ответ очень нужен. Сначала нам нужно знать некоторые правила класса Java.lang.String.

  1. Строковые литералы, напримерString str="java"; (мы используем только двойные кавычки) отличаются от String Object (мы используем новое ключевое слово), например String str=new String("java");

  2. Строка - неизменяемый объект т.е. если значение изменяется, новый объект создается и возвращается вам, например, см.replace() and replaceAll() функции и многое другое.

  3. Это создает проблему, заключающуюся в том, что многие объекты String в модификации, поэтому создатели Java придумали идею, которая получила название StringPool. StringPool хранится в области кучи, где будут храниться данные ссылки на объект, поскольку мы знаем, что StringChar[]( до Java 9 очень долго читать) илиbyte[]( после java 9 кратко читать).

  4. Строковые литералы хранятся в StringPool, а объекты String хранятся в обычной области объектов кучи.

  5. Если есть много инициализации объектной строки, куча JVM будет завершена только в строковых операциях, команда разработчиков Java предложила решение intern(), которое перемещает / изменяет ссылку памяти на StringPool.

    Программа: сравнение строковых ссылок на объекты

Еще одна хорошая ссылка для лучшего понимания java.lang.String

import java.util.*; 

class GFG { 
    public static void main(String[] args) 
    { 
      String siteName1 = "java.com";
        String siteName2 = "java.com";
        String siteName3 = new String("java.com");
        String siteName4 = new String("java.com").intern();
      
    System.out.println("siteName1:::"+Integer.toHexString(System.identityHashCode(siteName1)));
      System.out.println("siteName2:::"+Integer.toHexString(System.identityHashCode(siteName2)));
      System.out.println("siteName3 creation Of New Object Without Interned:::"+Integer.toHexString(System.identityHashCode(siteName3)));//must be Diffrent bcoz new Object In Heap Area
      System.out.println("siteName4 creation Of New Object With Interned:::"+Integer.toHexString(System.identityHashCode(siteName4)));//must be same MemoryAddress of siteName1,siteName2 and Interned, bcoz Objects Points to String pool Now
      
      System.out.println(siteName1 == siteName2); // true
      System.out.println(siteName1 == siteName3); // false this tells about lietral vs String Objects
      String siteName5 = siteName3.intern(); // Interning will not change Original Object but gives us a new Object
      
      System.out.println("siteName5 Interned from siteName3:::"+Integer.toHexString(System.identityHashCode(siteName5)));//must be same MemoryAddress of siteName1,siteName2 and Interned, bcoz Objects Points to String pool Now
      
      System.out.println(siteName1 == siteName3); // false this tells about Immutability
      System.out.println(siteName1 == siteName5); // true After Intering both are same
      System.out.println(siteName1 == siteName4); // true
      System.out.println(siteName5 == siteName4); // true
    } 
}
String str = new String("hello")

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

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

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

String str = "world";

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

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

Другие вопросы по тегам