Разница между строковым объектом и строковым литералом

В чем разница между

String str = new String("abc");

и

String str = "abc";

Ответ 1

Когда вы используете строковый литерал, строка может быть интернирована, но когда вы используете new String("..."), вы получаете новый строковый объект.

В этом примере оба строковых литерала ссылаются на один и тот же объект:

String a = "abc"; 
String b = "abc";
System.out.println(a == b);  // true

Здесь создаются 2 разных объекта, и они имеют разные ссылки:

String c = new String("abc");
String d = new String("abc");
System.out.println(c == d);  // false

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

Ответ 2

Строковый литерал - это концепция языка Java. Это строковый литерал:

"a String literal"

Объект String является отдельным экземпляром класса java.lang.String.

String s1 = "abcde";
String s2 = new String("abcde");
String s3 = "abcde";

Все действительны, но имеют небольшую разницу. s1 будет ссылаться на интернированный объект String. Это означает, что символьная последовательность "abcde" будет храниться в центральном месте, и всякий раз, когда один и тот же литерал "abcde" будет использоваться снова, JVM не будет создавать новый объект String, а использовать ссылку на кешированную строку.

s2 гарантируется новый объект String, поэтому в этом случае мы имеем:

s1 == s2 // is false
s1 == s3 // is true
s1.equals(s2) // is true

Ответ 3

Длинный ответ доступен здесь, поэтому я дам вам короткий.

Когда вы это сделаете:

String str = "abc";

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

С учетом следующего кода:

String str = "abc";
String str2 = "abc";
boolean identity = str == str2;

Когда вы проверяете идентификатор объекта, выполнив == (вы буквально спрашиваете: указывают ли эти две ссылки на один и тот же объект?), вы получаете true.

Однако вам не нужно intern() Strings. Вы можете принудительно создать создание нового Object в куче, выполнив следующее:

String str = new String("abc");
String str2 = new String("abc");
boolean identity = str == str2;

В этом случае str и str2 являются ссылками на разные Objects, ни один из которых не был интернирован, поэтому, когда вы тестируете идентификатор Object с помощью ==, вы получите false.

С точки зрения хорошей практики кодирования: не используйте == для проверки равенства строк, вместо этого используйте .equals().

Ответ 4

Поскольку строки неизменяемы, когда вы делаете:

String a = "xyz"

при создании строки JVM ищет в пуле строк, если уже существует строковое значение "xyz", если so 'a' будет просто ссылкой на эту строку и не будет создан новый объект String.

Но если вы скажете:

String a = new String("xyz")

вы заставляете JVM создавать новую ссылку String, даже если "xyz" находится в пуле.

Для получения дополнительной информации прочтите this.

Ответ 5

"abc" - буквальная строка.

В Java эти литеральные строки объединены внутри и один и тот же экземпляр String "abc" используется там, где у вас есть этот строковый литерал, объявленный в вашем коде. Таким образом, "abc" == "abc" всегда будет истинным, поскольку они оба являются одинаковыми экземплярами String.

Используя метод String.intern(), вы можете добавить любую строку, которая вам нравится, к внутренне объединенным строкам, они будут храниться в памяти до тех пор, пока java выходов.

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

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

Ответ 6

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

String st1 = new String();

или

String st2 = new String("Hello"); 
String st3 = new String("Hello");

Здесь st1, st2 и st3 - разные объекты.

То есть:

st1 == st2 // false
st1 == st3 // false
st2 == st3 // false

Поскольку st1, st2, st3 ссылаются на 3 разных объекта, а == проверяет равенство в ячейке памяти, следовательно, результат.

Но:

st1.equals(st2) // false
st2.equals(st3) // true

Здесь .equals() проверяет содержимое и содержимое st1 = "", st2 = "hello" и st3 = "hello". Следовательно, результат.

И в случае объявления String

String st = "hello";

Здесь вызывается метод intern() класса String и проверяется, находится ли "hello" в старом пуле, а если нет, он добавляется в внутренний пул, и если в общедоступном пуле есть "привет", st будет указывать на память существующего "hello".

Итак, в случае:

String st3 = "hello";
String st4 = "hello"; 

Здесь:

st3 == st4 // true

Потому что st3 и st4 указывают на тот же адрес памяти.

также:

st3.equals(st4);  // true as usual

Ответ 7

В первом случае создается два объекта.

Во втором случае это всего лишь один.

Хотя оба пути str относятся к "abc".

Ответ 8

Некоторая разборка всегда интересна...

$ cat Test.java 
public class Test {
    public static void main(String... args) {
        String abc = "abc";
        String def = new String("def");
    }
}

$ javap -c -v Test
Compiled from "Test.java"
public class Test extends java.lang.Object
  SourceFile: "Test.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = Method  #7.#16;  //  java/lang/Object."<init>":()V
const #2 = String  #17;     //  abc
const #3 = class   #18;     //  java/lang/String
const #4 = String  #19;     //  def
const #5 = Method  #3.#20;  //  java/lang/String."<init>":(Ljava/lang/String;)V
const #6 = class   #21;     //  Test
const #7 = class   #22;     //  java/lang/Object
const #8 = Asciz   <init>;
...

{
public Test(); ...    

public static void main(java.lang.String[]);
  Code:
   Stack=3, Locals=3, Args_size=1
    0:    ldc #2;           // Load string constant "abc"
    2:    astore_1          // Store top of stack onto local variable 1
    3:    new #3;           // class java/lang/String
    6:    dup               // duplicate top of stack
    7:    ldc #4;           // Load string constant "def"
    9:    invokespecial #5; // Invoke constructor
   12:    astore_2          // Store top of stack onto local variable 2
   13:    return
}

Ответ 9

В дополнение к уже опубликованным ответам также см. эту отличную статью о javaranch.

Ответ 10

Согласно Документация класса String, они эквивалентны.

Документация для String(String original) также гласит, что: если явная копия оригинала не нужна, использование этого конструктора необязательно, поскольку строки являются неизменяемыми.

Ищите другие ответы, потому что кажется, что документация Java вводит в заблуждение: (

Ответ 11

Ниже приведены некоторые сравнения:

String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");

System.out.println(s1 == s2); //true
System.out.println(s1.equals(s2)); //true

System.out.println(s1 == s3);   //false
System.out.println(s1.equals(s3)); //true

s3 = s3.intern();
System.out.println(s1 == s3); //true
System.out.println(s1.equals(s3)); //true

Когда intern() вызывается, ссылка изменяется.

Ответ 12

Существует тонкие различия между объектом String и строковым литералом.

String s = "abc"; // creates one String object and one reference variable

В этом простом случае "abc" войдет в пул, и s будет ссылаться на него.

String s = new String("abc"); // creates two objects,and one reference variable

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

Ответ 13

String s = new String("FFFF") создает 2 объекта: "FFFF" string и String объект, который указывает на строку "FFFF", поэтому он похож на указатель на указатель (ссылка на ссылку, я не увлекаюсь терминологией).

Говорят, вы никогда не должны использовать new String("FFFF")