Javaで文字列を比較するにはどうすればよいですか?

2009年02月05日に質問されました。  ·  閲覧回数 4M回  ·  ソース

Nathan H picture
2009年02月05日

これまで、プログラムで==演算子を使用して、すべての文字列を比較してきました。 しかし、バグが発生し、そのうちの1つを.equals()に変更して、バグを修正しました。

==悪いですか? いつ使用すべきで、使用すべきではありませんか? 違いは何ですか?

回答

Aaron Maenpaa picture
2009年02月05日
5652

== 、参照の同等性をテストします(それらが同じオブジェクトであるかどうか)。

.equals() 、値が等しいかどうかをテストします(論理的に「等しい」かどうか)。

Objects.equals()をチェックnullを呼び出す前に.equals()あなたは(でも利用可能JDK7のとして利用する必要はありませんので、グアバ)。

したがって、2つの文字列が同じ値であるかどうかをテストする場合は、おそらくObjects.equals()を使用することをお勧めします。

// These two have the same value
new String("test").equals("test") // --> true 

// ... but they are not the same object
new String("test") == "test" // --> false 

// ... neither are these
new String("test") == new String("test") // --> false 

// ... but these are because literals are interned by 
// the compiler and thus refer to the same object
"test" == "test" // --> true 

// ... string literals are concatenated by the compiler
// and the results are interned.
"test" == "te" + "st" // --> true

// ... but you should really just call Objects.equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Objects.equals(null, null) // --> true

あなたは、ほとんどObjects.equals()インターンされた文字列を扱っていることがまれな状況では、 ==使用できます。

JLS3.10.5から文字列リテラル

さらに、文字列リテラルは常にクラスString同じインスタンスをStringます。 これは、文字列リテラル(またはより一般的には定数式( §15.28 )の値である文字列)が、メソッドString.internを使用して、一意のインスタンスを共有するように「インターン」されるためです。

同様の例は、 JLS3.10.5-1にもあります。

考慮すべき他の方法

大文字と小文字を区別しないString.equalsIgnoreCase()値の同等性。

String.contentEquals()は、 Stringのコンテンツを任意のCharSequence (Java 1.5以降で使用可能のコンテンツと比較します。 等価比較を行う前にStringBufferなどを文字列に変換する必要がなくなりますが、nullチェックはユーザーに任せます。

Whatsit picture
2009年02月05日
731

==オブジェクト参照をテストし、 .equals()は文字列値をテストします。

==値を比較しているように見えることがあります。これは、Javaが舞台裏でいくつかの処理を実行して、同一のインライン文字列が実際に同じオブジェクトであることを確認するためです。

例えば:

String fooString1 = new String("foo");
String fooString2 = new String("foo");

// Evaluates to false
fooString1 == fooString2;

// Evaluates to true
fooString1.equals(fooString2);

// Evaluates to true, because Java uses the same object
"bar" == "bar";

ただし、nullには注意してください。

==null文字列を正常に処理しますが、null文字列から.equals()を呼び出すと、例外が発生します。

String nullString1 = null;
String nullString2 = null;

// Evaluates to true
System.out.print(nullString1 == nullString2);

// Throws a NullPointerException
System.out.print(nullString1.equals(nullString2));

したがって、 fooString1がnullである可能性があることがわかっている場合は、次のように記述して読者に伝えてください。

System.out.print(fooString1 != null && fooString1.equals("bar"));

以下は短いですが、nullをチェックすることはあまり明白ではありません。

System.out.print("bar".equals(fooString1));  // "bar" is never null
System.out.print(Objects.equals(fooString1, "bar"));  // Java 7 required
Ganesh picture
2013年01月02日
448

==オブジェクト参照を比較します。

.equals()文字列値を比較します。

次の場合のように、 ==が文字列値を比較しているように見えることがあります。

String a="Test";
String b="Test";
if(a==b) ===> true

これは、文字列リテラルを作成すると、JVMが最初に文字列プールでそのリテラルを検索し、一致するものが見つかった場合、同じ参照が新しい文字列に与えられるためです。 このため、次のようになります。

(a == b)===> true

                       String Pool
     b -----------------> "test" <-----------------a

ただし、次の場合、 ==失敗します。

String a="test";
String b=new String("test");
if (a==b) ===> false

この場合、 new String("test") 、ステートメントnew Stringがヒープ上に作成され、その参照はbに与えられるため、 bにはヒープ上の参照が与えられます。 、文字列プールにはありません。

これで、 aは文字列プール内の文字列を指し、 bはヒープ上の文字列を指します。 そのため、次のようになります。

if(a == b)===> false。

                String Pool
     "test" <-------------------- a

                   Heap
     "test" <-------------------- b

.equals()常にStringの値を比較するため、どちらの場合もtrueになります。

String a="Test";
String b="Test";
if(a.equals(b)) ===> true

String a="test";
String b=new String("test");
if(a.equals(b)) ===> true

したがって、 .equals()を使用する方が常に優れています。

Clayton picture
2009年02月05日
224

==演算子は、2つの文字列がまったく同じオブジェクトであるかどうかを確認します。

.equals()メソッドは、2つの文字列の値が同じかどうかを確認します。

Faisal Feroz picture
2009年02月05日
182

Javaの文字列は不変です。 つまり、文字列を変更/変更しようとすると、新しいインスタンスが取得されます。 元の文字列を変更することはできません。 これは、これらの文字列インスタンスをキャッシュできるようにするために行われました。 一般的なプログラムには多くの文字列参照が含まれており、これらのインスタンスをキャッシュすると、メモリフットプリントが減少し、プログラムのパフォーマンスが向上します。

文字列の比較に==演算子を使用する場合、文字列の内容を比較するのではなく、実際にはメモリアドレスを比較します。 両方が等しい場合はtrueを返し、そうでない場合はfalseを返します。 文字列のequalsは、文字列の内容を比較します。

したがって、問題は、すべての文字列がシステムにキャッシュされている場合、 ==がfalseを返すのに対し、equalsはtrueを返すのはなぜですか? まあ、これは可能です。 String str = new String("Testing")ような新しい文字列を作成すると、キャッシュに同じ内容の文字列がすでに含まれている場合でも、キャッシュに新しい文字列が作成されることになります。 つまり、 "MyString" == new String("MyString")は常にfalseを返します。

Javaは、文字列をキャッシュの一部にするために文字列で使用できる関数intern()についても説明しているため、 "MyString" == new String("MyString").intern()はtrueを返します。

注:==演算子は、2つのメモリアドレスを比較しているという理由だけで、等しいよりもはるかに高速ですが、コードがコード内に新しい文字列インスタンスを作成していないことを確認する必要があります。 そうしないと、バグが発生します。

duffymo picture
2009年02月05日
147
String a = new String("foo");
String b = new String("foo");
System.out.println(a == b); // prints false
System.out.println(a.equals(b)); // prints true

理由を理解してください。 これは、 ==比較では参照のみが比較されるためです。 equals()メソッドは、内容の文字ごとの比較を行います。

abに対してnewを呼び出すと、それぞれが文字列テーブルの"foo"を指す新しい参照を取得します。 参照は異なりますが、内容は同じです。

Uri picture
2009年02月05日
128

ええ、それは悪いです...

==は、2つの文字列参照がまったく同じオブジェクトであることを意味します。 Javaが一種のリテラルテーブルを保持しているため(これはそうです)、これが当てはまると聞いたことがあるかもしれませんが、常にそうであるとは限りません。 一部の文字列は、他の文字列などから構築されたさまざまな方法でロードされるため、2つの同一の文字列が同じ場所に格納されていると思い込まないでください。

Equalsはあなたのために本当の比較をします。

cletus picture
2009年02月05日
124

はい、 ==は文字列の比較には適していません(正規のオブジェクトであることがわかっている場合を除き、実際にはすべてのオブジェクト)。 ==オブジェクト参照を比較するだけです。 .equals()は同等性をテストします。 文字列の場合、多くの場合同じになりますが、ご存知のとおり、常に保証されているわけではありません。

Saurabh Agarwal picture
2013年04月02日
120

Javaには、JavaがStringオブジェクトのメモリ割り当てを管理するStringプールがあります。 Javaの文字列プールを参照してください

==演算子を使用して2つのオブジェクトをチェック(比較)すると、アドレスの同等性が文字列プールと比較されます。 2つのStringオブジェクトが同じアドレス参照を持っている場合はtrue返し、そうでない場合はfalse返します。 ただし、2つのStringオブジェクトの内容を比較する場合は、 equalsメソッドをオーバーライドする必要があります。

equalsは実際にはObjectクラスのメソッドですが、Stringクラスにオーバーライドされ、オブジェクトの内容を比較する新しい定義が与えられます。

Example:
    stringObjectOne.equals(stringObjectTwo);

ただし、Stringの場合を尊重することに注意してください。 大文字と小文字を区別しない比較が必要な場合は、StringクラスのequalsIgnoreCaseメソッドを使用する必要があります。

どれどれ:

String one   = "HELLO"; 
String two   = "HELLO"; 
String three = new String("HELLO"); 
String four  = "hello"; 

one == two;   // TRUE
one == three; // FALSE
one == four;  // FALSE

one.equals(two);            // TRUE
one.equals(three);          // TRUE
one.equals(four);           // FALSE
one.equalsIgnoreCase(four); // TRUE
pgras picture
2009年02月05日
103

私はzacheratesからの答えに同意します。

しかし、あなたができることは、非リテラル文字列でintern()を呼び出すことです。

zacheratesの例から:

// ... but they are not the same object
new String("test") == "test" ==> false 

非リテラル文字列の等式をインターンした場合、 true

new String("test").intern() == "test" ==> true