В чем разница между
String str = new String("abc");
и
String str = "abc";
В чем разница между
String str = new String("abc");
и
String str = "abc";
Когда вы используете строковый литерал, строка может быть интернирована, но когда вы используете 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
В общем, вы должны использовать текстовую литературу, когда это возможно. Его легче читать, и он дает компилятору возможность оптимизировать ваш код.
Строковый литерал - это концепция языка 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
Длинный ответ доступен здесь, поэтому я дам вам короткий.
Когда вы это сделаете:
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()
.
Поскольку строки неизменяемы, когда вы делаете:
String a = "xyz"
при создании строки JVM ищет в пуле строк, если уже существует строковое значение "xyz"
, если so 'a'
будет просто ссылкой на эту строку и не будет создан новый объект String.
Но если вы скажете:
String a = new String("xyz")
вы заставляете JVM создавать новую ссылку String
, даже если "xyz"
находится в пуле.
Для получения дополнительной информации прочтите this.
"abc"
- буквальная строка.
В Java эти литеральные строки объединены внутри и один и тот же экземпляр String "abc"
используется там, где у вас есть этот строковый литерал, объявленный в вашем коде. Таким образом, "abc" == "abc"
всегда будет истинным, поскольку они оба являются одинаковыми экземплярами String.
Используя метод String.intern()
, вы можете добавить любую строку, которая вам нравится, к внутренне объединенным строкам, они будут храниться в памяти до тех пор, пока java выходов.
С другой стороны, использование new String("abc")
создаст новый строковый объект в памяти, который логически совпадает с литералом "abc"
.
"abc" == new String("abc")
всегда будет ложным, так как хотя они логически равны, они относятся к разным экземплярам.
Обтекание строкового конструктора вокруг строкового литерала не имеет значения, оно просто бесполезно использует больше памяти, чем нужно.
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
В первом случае создается два объекта.
Во втором случае это всего лишь один.
Хотя оба пути str
относятся к "abc"
.
Некоторая разборка всегда интересна...
$ 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
}
В дополнение к уже опубликованным ответам также см. эту отличную статью о javaranch.
Согласно Документация класса String, они эквивалентны.
Документация для String(String original)
также гласит, что: если явная копия оригинала не нужна, использование этого конструктора необязательно, поскольку строки являются неизменяемыми.
Ищите другие ответы, потому что кажется, что документация Java вводит в заблуждение: (
Ниже приведены некоторые сравнения:
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()
вызывается, ссылка изменяется.
Существует тонкие различия между объектом 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" будет
размещаться в пуле.
String s = new String("FFFF")
создает 2 объекта: "FFFF"
string и String
объект, который указывает на строку "FFFF"
, поэтому он похож на указатель на указатель (ссылка на ссылку, я не увлекаюсь терминологией).
Говорят, вы никогда не должны использовать new String("FFFF")