違いは何ですか
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
一般に、可能であれば文字列リテラル表記を使用する必要があります。読みやすく、コンパイラがコードを最適化する機会を与えます。
A String literal is a Java language concept. This is a String literal:
"a String literal"
A String object is an individual instance of the java.lang.String
class.
String s1 = "abcde";
String s2 = new String("abcde");
String s3 = "abcde";
All are valid, but have a slight difference. s1
will refer to an interned String object. This means, that the character sequence "abcde"
will be stored at a central place, and whenever the same literal "abcde"
is used again, the JVM will not create a new String object but use the reference of the cached String.
s2
is guranteed to be a new String object, so in this case we have:
s1 == s2 // is false
s1 == s3 // is true
s1.equals(s2) // is true
長い答えはここにありますので、短い答えをあげましょう。
これを行うとき:
String str = "abc";
Stringintern()
でメソッドを呼び出しています。このメソッドは、オブジェクトの内部プールを参照します。呼び出した文字列がすでにプールに存在する場合、その文字列への参照がに割り当てられます。そうでない場合は、新しいものがプールに配置され、それへの参照がに割り当てられます。String
intern()
String
str
String
str
次のコードが与えられます:
String str = "abc";
String str2 = "abc";
boolean identity = str == str2;
==
(文字通り質問している:これらの2つの参照は同じオブジェクトを指しているのか?)を実行してオブジェクトのIDを確認すると、が得られtrue
ます。
ただし、する必要はありませんintern()
Strings
。Object
これを行うことで、ヒープ上の新しいものに作成を強制できます。
String str = new String("abc");
String str2 = new String("abc");
boolean identity = str == str2;
この例では、str
とstr2
は異なるへの参照Objects
であり、どちらもインターンされObject
ていないため、を使用してIDをテストする==
と、が取得されますfalse
。
優れたコーディング手法の観点から、文字列の同等性をチェックするためにを使用せず、代わりにを使用してください。==
.equals()
文字列は不変であるため、次のようにします。
String a = "xyz"
文字列の作成中に、JVM は文字列値が既に存在するかどうかを文字列のプールで検索します。存在する"xyz"
場合'a'
は単にその文字列の参照となり、新しい String オブジェクトは作成されません。
しかし、あなたが言うなら:
String a = new String("xyz")
String
プール内にある場合でも、JVM に新しい参照を強制的に作成"xyz"
させます。
詳細については、こちらをお読みください。
"abc"
リテラル文字列です。
Java では、これらのリテラル文字列は内部的にプール"abc"
され、コード内でその文字列リテラルが宣言されている場合は常に、同じ String インスタンスが使用されます。どちら"abc" == "abc"
も同じ String インスタンスであるため、常に true になります。
String.intern()
内部でプールされた文字列に任意の文字列を追加できるメソッドを使用すると、これらは Java が終了するまでメモリに保持されます。
一方、 usingはメモリ内に新しい文字列オブジェクトを作成します。これは論理的にリテラル
new String("abc")
と同じです。これらは論理的には同じですが、異なるインスタンスを参照しているため、常に false になります。"abc"
"abc" == new String("abc")
文字列リテラルを文字列コンストラクタでラップしても意味がありません。必要以上のメモリを不必要に使用するだけです。
最初のケースでは、2 つのオブジェクトが作成されます。
2 番目のケースでは、1 つだけです。
どちらの方法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")
"FFFF"
文字列と文字列String
を指すオブジェクトの2つのオブジェクトを作成する"FFFF"
ため、ポインターからポインターへのようなものです(参照への参照、用語には熱心ではありません)。
絶対に使ってはいけないと言われていますnew String("FFFF")