違いは何ですか
String str = new String("abc");
そして
String str = "abc";
文字列リテラルを使用すると、文字列は interned になりますが、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はJava言語の概念です。これは文字列リテラルです。
"a String literal"
--- StringオブジェクトはJava.lang.String
クラスの個々のインスタンスです。
String s1 = "abcde";
String s2 = new String("abcde");
String s3 = "abcde";
すべて有効ですが、わずかな違いがあります。 s1
はinterned Stringオブジェクトを参照します。つまり、文字シーケンス"abcde"
は中央の場所に格納され、同じリテラル"abcde"
が再度使用されるときはいつでも、JVMは新しいStringオブジェクトを作成せずにcache Stringの参照を使用します。
s2
は新しいStringオブジェクトであることが保証されているので、この場合は次のようになります。
s1 == s2 // is false
s1 == s3 // is true
s1.equals(s2) // is true
長い答えがあります こちら だから、短い答えをあげましょう。
これをするとき:
String str = "abc";
String でintern()
メソッドを呼び出しています。このメソッドは、String
オブジェクトの内部プールを参照します。 intern()
を呼び出した文字列がすでにプールに存在する場合は、そのString
への参照がstr
に割り当てられます。そうでない場合は、新しいString
がプールに配置され、それへの参照がstr
に割り当てられます。
次のコードがあるとします。
String str = "abc";
String str2 = "abc";
boolean identity = str == str2;
==
を実行してオブジェクトの同一性を確認すると(文字通り、これら2つの参照は同じオブジェクトを指していますか?)、true
が返されます。
ただし、intern()
Strings
にはは必要ありません。こうすることで、ヒープ上の新しいObject
を強制的に作成できます。
String str = new String("abc");
String str2 = new String("abc");
boolean identity = str == str2;
この例では、str
とstr2
は異なるObjects
への参照であり、どちらもインターンされていないため、==
を使用してObject
の同一性をテストするときfalse
を取得します。
適切なコーディング慣行に関しては、donotで文字列が等しいかどうかをチェックするために==
を使用してください。代わりに.equals()
を使用してください。
文字列は不変なので、次のようにします。
String a = "xyz"
文字列の作成中に、JVMは、文字列値"xyz"
がすでに存在する場合は文字列のプールを検索し、存在する場合は'a'
は単にその文字列の参照になり、新しいStringオブジェクトは作成されません。
しかしあなたが言うなら:
String a = new String("xyz")
"xyz"
がそのプール内にある場合でも、JVMに新しいString
参照を強制的に作成させます。
詳しくは this を読んでください。
"abc"
はリテラル文字列です。
Javaでは、これらのリテラル文字列は内部的にプールされ、コード内でその文字列リテラルが宣言されている場所では、"abc"
の同じStringインスタンスが使用されます。したがって、"abc" == "abc"
は両方とも同じStringインスタンスであるため、常にtrueになります。
String.intern()
メソッドを使用すると、内部的にプールされた文字列に好きな文字列を追加できます。これらはJavaが終了するまでメモリ内に保持されます。
一方、new String("abc")
を使用すると、メモリ内に新しい文字列オブジェクトが作成されます。これは、"abc"
リテラルと論理的に同じです。 "abc" == new String("abc")
は常にfalseになります。論理的には同じですが、異なるインスタンスを参照しているからです。
文字列リテラルの周りにStringコンストラクタをラップすることには意味がありません。不必要に必要以上にメモリを消費するだけです。
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";
ここでは、String
クラスのintern()
メソッドが呼び出され、"hello"
がインターンプールにあるかどうかチェックし、そうでない場合はインターンプールに追加され、 "hello"がインターンプールにある場合、st
は既存のメモリを指します"hello"
。
だからの場合:
String st3 = "hello";
String st4 = "hello";
ここに:
st3 == st4 // true
なぜならst3
とst4
は同じメモリアドレスを指しているからです。
また:
st3.equals(st4); // true as usual
最初のケースでは、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の this 優秀な記事も参照してください。
String class documentation によると、これらは同等です。
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
オブジェクト。これらは"FFFF"
文字列を指しています。そのため、これはポインタへのポインタのようなものです(参照への参照、用語には賛成しません)。
決してnew String("FFFF")
を使うべきではないと言われています