web-dev-qa-db-ja.com

文字列オブジェクトと文字列リテラルの違い

違いは何ですか

String str = new String("abc");

そして

String str = "abc";
235
user395617

文字列リテラルを使用すると、文字列は 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

一般に、可能な場合は文字列リテラル表記を使用する必要があります。読みやすく、コンパイラにコードを最適化する機会を与えます。

202
Mark Byers

A String literalはJava言語の概念です。これは文字列リテラルです。

"a String literal"

--- StringオブジェクトJava.lang.Stringクラスの個々のインスタンスです。

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

すべて有効ですが、わずかな違いがあります。 s1interned Stringオブジェクトを参照します。つまり、文字シーケンス"abcde"は中央の場所に格納され、同じリテラル"abcde"が再度使用されるときはいつでも、JVMは新しいStringオブジェクトを作成せずにcache Stringの参照を使用します。

s2新しいStringオブジェクトであることが保証されているので、この場合は次のようになります。

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

長い答えがあります こちら だから、短い答えをあげましょう。

これをするとき:

String str = "abc";

Stringintern()メソッドを呼び出しています。このメソッドは、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;

この例では、strstr2は異なるObjectsへの参照であり、どちらもインターンされていないため、==を使用してObjectの同一性をテストするときfalseを取得します。

適切なコーディング慣行に関しては、donotで文字列が等しいかどうかをチェックするために==を使用してください。代わりに.equals()を使用してください。

40
Jon

文字列は不変なので、次のようにします。

String a = "xyz"

文字列の作成中に、JVMは、文字列値"xyz"がすでに存在する場合は文字列のプールを検索し、存在する場合は'a'は単にその文字列の参照になり、新しいStringオブジェクトは作成されません。

しかしあなたが言うなら:

String a = new String("xyz")

"xyz"がそのプール内にある場合でも、JVMに新しいString参照を強制的に作成させます。

詳しくは this を読んでください。

35
Awin

"abc"はリテラル文字列です。

Javaでは、これらのリテラル文字列は内部的にプールされ、コード内でその文字列リテラルが宣言されている場所では、"abc"の同じStringインスタンスが使用されます。したがって、"abc" == "abc"は両方とも同じStringインスタンスであるため、常にtrueになります。

String.intern() メソッドを使用すると、内部的にプールされた文字列に好きな文字列を追加できます。これらはJavaが終了するまでメモリ内に保持されます。

一方、new String("abc")を使用すると、メモリ内に新しい文字列オブジェクトが作成されます。これは、"abc"リテラルと論理的に同じです。 "abc" == new String("abc")は常にfalseになります。論理的には同じですが、異なるインスタンスを参照しているからです。

文字列リテラルの周りにStringコンストラクタをラップすることには意味がありません。不必要に必要以上にメモリを消費するだけです。

17
krock

Stringは他のプログラミング言語とは異なるJavaのクラスです。すべてのクラスについて、オブジェクトの宣言と初期化は

String st1 = new String();

または

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

ここで、st1st2、およびst3は異なるオブジェクトです。

あれは:

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

st1st2st3は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

なぜならst3st4は同じメモリアドレスを指しているからです。

また:

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

最初のケースでは、2つのオブジェクトが作成されています。

後者の場合、それは1つだけです。

両方の方法でstr"abc"を参照していますが。

6
sushil bharwani

いくつかの分解は常に面白いです...

$ 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
}
5
aioobe

すでに投稿された回答に加えて、javaranchの this 優秀な記事も参照してください。

5
Zaki

String class documentation によると、これらは同等です。

String(String original)のドキュメントには次のようにも書かれています:オリジナルの明示的なコピーが必要な場合を除き、文字列は不変であるため、このコンストラクターの使用は不要です。

Javaのドキュメントは誤解を招くように思われるため、他の応答を探してください:(

3
Michał Niklas

以下はいくつかの比較です。

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()が呼び出されると、参照は変更されます。

2
JavaFreak

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"がプールに配置されます。

1
Kamal

String s = new String("FFFF")は2つのオブジェクトを作成します:"FFFF"文字列とStringオブジェクト。これらは"FFFF"文字列を指しています。そのため、これはポインタへのポインタのようなものです(参照への参照、用語には賛成しません)。

決してnew String("FFFF")を使うべきではないと言われています

0
foret