これまで私のプログラムでは==
演算子を使ってすべての文字列を比較してきました。しかし、私はバグに遭遇し、代わりにそれらの1つを.equals()
に変更し、そしてそれはバグを修正しました。
==
は悪いですか?いつ使うべきで、使わないべきですか?違いは何ですか?
==
は、参照が等しいかどうかをテストします(それらが同じオブジェクトかどうか)。
.equals()
は値が等しいかどうかをテストします(それらが論理的に「等しい」かどうか)。
Objects.equals() は.equals()
を呼び出す前にnull
をチェックします。そのため、必要はありません(JDK 7以降で利用可能、 Guava でも利用可能)。
String.contentEquals() は、String
の内容と任意のCharSequence
の内容(Java 1.5以降で使用可能)を比較します。
したがって、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()
を使いたいです。 rare あなたが know を扱っている状況では、 interned 文字列を扱っているので、あなたはcanを==
として使います。
さらに、文字列リテラルは常にクラス
String
のsameインスタンスを参照します。これは、文字列リテラル、より一般的には定数式( §15.28 )の値である文字列が、メソッドString.intern
を使って一意のインスタンスを共有するために "インターンされる"ためです。
同様の例が JLS 3.10.5-1 にもあります。
==
はオブジェクト参照をテストし、.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"));
以下はより短いですが、(Java 7から)nullをチェックすることはそれほど明白ではありません。
System.out.print(Objects.equals(fooString1, "bar"));
==
はオブジェクト参照を比較します。
.equals()
は文字列値を比較します。
以下のように、==
が文字列値の比較を幻想にすることがあります。
String a="Test";
String b="Test";
if(a==b) ===> true
これは、文字列リテラルを作成すると、JVMは最初に文字列プールでそのリテラルを検索し、一致するものが見つかった場合は同じ文字列が新しい文字列に与えられるためです。これにより、次のようになります。
(a == b)===>真
String Pool
b -----------------> "test" <-----------------a
ただし、次の場合に==
は失敗します。
String a="test";
String b=new String("test");
if (a==b) ===> false
この場合、new String("test")
のステートメントnewヒープはヒープ上に作成され、その参照はb
に与えられるので、b
はStringプールではなくヒープ上の参照を与えられます。
a
はヒープ上のStringを指しているのに対し、b
はStringプール内のStringを指しています。そのために私たちは得ます:
if(a == b)===> false。
String Pool
"test" <-------------------- a
Heap
"test" <-------------------- b
.equals()
は常にStringの値を比較するので、どちらの場合もそうです。
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()
を使うのは常に良いことです。
==
演算子は、2つの文字列がまったく同じオブジェクトかどうかを確認します。
.equals()
メソッドは2つの文字列が同じ値を持っているかどうかをチェックします。
Javaの文字列は不変です。つまり、文字列を変更または修正しようとするたびに、新しいインスタンスが取得されます。元の文字列は変更できません。これらの文字列インスタンスをキャッシュできるようにこれが行われました。一般的なプログラムには多くの文字列参照が含まれており、これらのインスタンスをキャッシュすると、メモリ使用量を減らしてプログラムのパフォーマンスを向上させることができます。
文字列比較に==演算子を使用するときは、文字列の内容を比較しているのではなく、実際にはメモリアドレスを比較しています。両者が等しい場合はtrue、falseを返します。文字列と等しいのに対して文字列の内容を比較します。
問題は、すべての文字列がシステムにキャッシュされている場合、==
がfalseを返すのに対し、equalsがtrueを返すのはどうしてですか。まあ、これは可能です。 String str = new String("Testing")
のように新しい文字列を作成すると、キャッシュに同じ内容の文字列がすでに含まれている場合でも、キャッシュに新しい文字列を作成することになります。要するに"MyString" == new String("MyString")
は常にfalseを返します。
Javaは文字列をキャッシュの一部にするために文字列に対して使用できる関数intern()についても話します。したがって、"MyString" == new String("MyString").intern()
はtrueを返します。
注:==演算子は、2つのメモリアドレスを比較しているという理由だけで、equalsよりもはるかに高速ですが、コードがコード内に新しいStringインスタンスを作成していないことを確認する必要があります。さもなければあなたはバグに遭遇するでしょう。
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()
メソッドは、内容を文字ごとに比較します。
a
およびb
に対してnewを呼び出すと、それぞれが文字列テーブルの"foo"
を指す新しい参照を取得します。参照は異なりますが、内容は同じです。
ええ、それは悪いです...
==
は、2つの文字列参照がまったく同じオブジェクトであることを意味します。 Javaがリテラルテーブルのようなものを保持しているため(これはそうである)、これは事実であると聞いたことがあるかもしれませんが、それは必ずしもそうではありません。いくつかの文字列は異なる方法でロードされ、他の文字列などから構築されます。そのため、2つの同一の文字列が同じ場所に格納されているとは限りません。
Equalsはあなたにとって本当の比較をします。
はい、==
は文字列の比較には適していません(正規のものであることがわかっている場合を除き、実際には任意のオブジェクト)。 ==
はオブジェクト参照を比較するだけです。 .equals()
は等価性をテストします。文字列の場合、多くの場合それらは同じになりますが、あなたが発見したように、それは必ずしも保証されていません。
JavaにはStringプールがあり、その下でJavaがStringオブジェクトのメモリ割り当てを管理します。 Javaの文字列プールを参照してください
==
演算子を使用して2つのオブジェクトをチェック(比較)するとき、アドレスの等価性を文字列プールと比較します。 2つのStringオブジェクトが同じアドレス参照を持つ場合はtrue
を返し、それ以外の場合はfalse
を返します。しかし、2つのStringオブジェクトの内容を比較したい場合は、equals
メソッドをオーバーライドする必要があります。
equals
は実際にはObjectクラスのメソッドですが、Stringクラスにオーバーライドされ、objectの内容を比較する新しい定義が与えられています。
Example:
stringObjectOne.equals(stringObjectTwo);
しかし、注意してくださいそれは文字列の場合を尊重します。大文字と小文字を区別しないで比較したい場合は、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
==
はJava の中のオブジェクト参照を比較します、そしてそれはString
オブジェクトのための例外ではありません。
オブジェクトの実際の内容(String
を含む)を比較するには、equals
メソッドを使用しなければなりません 。
==
を使用した2つのString
オブジェクトの比較がtrue
であることが判明した場合、それはString
オブジェクトがインターンされていて、Java仮想マシンがString
の同じインスタンスを指しているためです。同じ内容を含むString
オブジェクトを別のString
オブジェクトと比較して、==
を使用してtrue
として評価することを期待してはいけません。
私は、学者からの回答に同意します。
しかし、あなたができることはあなたの非リテラル文字列でintern()
を呼び出すことです。
Zacheratesの例から:
// ... but they are not the same object
new String("test") == "test" ==> false
文字列でないリテラルの同等性がtrue
である場合
new String("test").intern() == "test" ==> true
.equals()
はクラス内のデータを比較します(関数が実装されていると仮定して)。 ==
はポインタの位置(メモリ内のオブジェクトの位置)を比較します。
両方のオブジェクト(PRIMITIVESについては話していない)が同じオブジェクトインスタンスを指している場合、==
はtrueを返します。 2つのオブジェクトに同じデータが含まれている場合、.equals()
はtrueを返します equals()
とJavaの==
それはあなたを助けるかもしれません。
2つのオブジェクト(この場合は文字列)がメモリ内の同じオブジェクトを参照しているかどうかにかかわらず、==
は reference equalityチェックを実行します。
equals()
メソッドは2つのオブジェクトの contents または states が同じかどうかをチェックします。
明らかに==
は高速ですが、2つのString
が同じテキストを保持しているかどうかを伝えたいだけの場合、多くの場合誤った結果をもたらすでしょう。
間違いなくequals()
メソッドの使用をお勧めします。
性能について心配しないでください。 String.equals()
の使用を推奨するいくつかのこと:
String.equals()
の実装は最初に参照の等価性をチェックし(==
を使って)、2つの文字列が参照によって同じであれば、それ以上の計算は行われません!String.equals()
は次に文字列の長さをチェックします。 String
クラスは文字列の長さを格納するため、これも高速な操作です。文字やコードポイントを数える必要はありません。長さが異なる場合、それ以上のチェックは実行されません。それらが等しくならないことがわかります。すべてのことを言って終わったとき、たとえ文字列がインターンであることを保証していたとしても、equals()
メソッドを使うことはまだオーバーヘッドではないと思われるので、絶対にお勧めの方法です。効率的な参照チェックが必要な場合は、言語仕様と実装によって同じenum値が(参照によって)同じオブジェクトになることが保証されている場合はenumを使用してください。
私のように、Javaを使い始めたときは、2つのStringインスタンスが等しいかどうかをテストするために "=="演算子を使いたかったのですが、良くも悪くも、これはJavaで正しい方法ではありません。
このチュートリアルでは、Java文字列を正しく比較するためのいくつかの異なる方法を紹介します。私が最もよく使う方法から始めます。このJava String比較チュートリアルの最後に、Javaストリングを比較するときに「==」演算子が機能しない理由についても説明します。
オプション1:equalsメソッドとのJava文字列比較 ほとんどの場合(おそらく95%の時間)、次のようにJava Stringクラスのequalsメソッドと文字列を比較します。
if (string1.equals(string2))
このString equalsメソッドは、2つのJava文字列を調べ、それらにまったく同じ文字列が含まれている場合、それらは等しいと見なされます。
次のテストを実行した場合、equalsメソッドを使用した簡単な文字列比較の例を見ると、2つの文字列はまったく同じではないため、等しいとは見なされません(文字の大文字と小文字は異なります)。
String string1 = "foo";
String string2 = "FOO";
if (string1.equals(string2))
{
// this line will not print because the
// Java string equals method returns false:
System.out.println("The two strings are the same.")
}
しかし、2つの文字列がまったく同じ文字列を含んでいる場合、equalsメソッドはこの例のようにtrueを返します。
String string1 = "foo";
String string2 = "foo";
// test for equality with the Java string equals method
if (string1.equals(string2))
{
// this line WILL print
System.out.println("The two strings are the same.")
}
オプション2:equalsIgnoreCaseメソッドとの文字列比較
いくつかの文字列比較テストでは、文字列が大文字か小文字かを無視したいでしょう。大文字と小文字を区別しないで文字列の等価性をテストする場合は、次のようにStringクラスのequalsIgnoreCaseメソッドを使用します。
String string1 = "foo";
String string2 = "FOO";
// Java string compare while ignoring case
if (string1.equalsIgnoreCase(string2))
{
// this line WILL print
System.out.println("Ignoring case, the two strings are the same.")
}
オプション3:compareToメソッドとのJava文字列比較
Java文字列を比較するための、あまり一般的ではない3つ目の方法もあります。それは、StringクラスのcompareToメソッドを使用する方法です。 2つの文字列がまったく同じ場合、compareToメソッドは値0(ゼロ)を返します。これは、このString比較アプローチがどのようなものであるかを示す簡単な例です。
String string1 = "foo bar";
String string2 = "foo bar";
// Java string compare example
if (string1.compareTo(string2) == 0)
{
// this line WILL print
System.out.println("The two strings are the same.")
}
私はJavaにおけるこの同等性の概念について書いている間、Java言語は基本Java Objectクラスにequalsメソッドを含むことに注意することは重要です。独自のオブジェクトを作成していて、そのオブジェクトの2つのインスタンスが「等しい」かどうかを確認する手段を提供したい場合は、常にクラス内でこのequalsメソッドをオーバーライド(および実装)する必要があります。 String equalsメソッドでのこの等価/比較動作).
この ==、.equals()、compareTo()、およびcompare() を見てみるとよいでしょう。
関数:
public float simpleSimilarity(String u, String v) {
String[] a = u.split(" ");
String[] b = v.split(" ");
long correct = 0;
int minLen = Math.min(a.length, b.length);
for (int i = 0; i < minLen; i++) {
String aa = a[i];
String bb = b[i];
int minWordLength = Math.min(aa.length(), bb.length());
for (int j = 0; j < minWordLength; j++) {
if (aa.charAt(j) == bb.charAt(j)) {
correct++;
}
}
}
return (float) (((double) correct) / Math.max(u.length(), v.length()));
}
テスト:
String a = "This is the first string.";
String b = "this is not 1st string!";
// for exact string comparison, use .equals
boolean exact = a.equals(b);
// For similarity check, there are libraries for this
// Here I'll try a simple example I wrote
float similarity = simple_similarity(a,b);
==
演算子は、2つの参照が同じオブジェクトを指しているかどうかを確認します。 .equals()
は実際の文字列の内容(値)を確認します。
.equals()
メソッドはクラスObject
(全クラスのスーパークラス)に属しています。あなたはあなたのクラスの必要条件に従ってそれをオーバーライドする必要があります、しかしStringのためにそれはすでに実装されていて、そしてそれは2つのストリングが同じ値を持っているかどうかチェックします。
ケース1
String s1 = "Stack Overflow";
String s2 = "Stack Overflow";
s1 == s2; //true
s1.equals(s2); //true
理由:NULLなしで作成された文字列リテラルは、ヒープのpermgen領域の文字列プールに格納されます。したがって、s1とs2はどちらもプール内の同じオブジェクトを指しています。
ケース2
String s1 = new String("Stack Overflow");
String s2 = new String("Stack Overflow");
s1 == s2; //false
s1.equals(s2); //true
理由:new
キーワードを使用してStringオブジェクトを作成した場合は、ヒープ上で個別のスペースが割り当てられます。
==
はオブジェクトの参照値を比較しますが、Java.lang.String
クラスに存在するequals()
メソッドはString
オブジェクトの内容を(別のオブジェクトと)比較します。
String
を定義するとき、あなたはオブジェクトを定義すると思います。だからあなたは.equals()
を使う必要があります。プリミティブデータ型を使用するときは==
を使用しますが、String
(および任意のオブジェクト)では.equals()
を使用する必要があります。
equals()
メソッドがJava.lang.Object
クラスに存在し、オブジェクトの状態の等価性をチェックすることが期待されているならば!つまり、オブジェクトの内容です。 ==
演算子は実際のオブジェクトインスタンスをチェックすることが期待されていますが同じであるかどうか。
例
str1
とstr2
という2つの異なる参照変数を考えます。
str1 = new String("abc");
str2 = new String("abc");
equals()
を使う場合
System.out.println((str1.equals(str2))?"TRUE":"FALSE");
==
を使用すると、出力はTRUE
となります。
System.out.println((str1==str2) ? "TRUE" : "FALSE");
これで、FALSE
が出力として取得されます。なぜなら、両方のstr1
とstr2
は、同じ文字列コンテンツを共有していても、2つの異なるオブジェクトを指しているからです。 new String()
のために毎回新しいオブジェクトが作成されます。
演算子 == は常に オブジェクト参照比較 を意味しますが、Stringクラス .equals() メソッドは コンテンツ比較 にオーバーライドされます。
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // It prints false (reference comparison)
System.out.println(s1.equals(s2)); // It prints true (content comparison)
compareTo()
メソッドを使って2つの文字列を比較することもできます。 compareToの結果が0の場合、2つの文字列は等しく、それ以外の場合は比較される文字列は等しくありません。
==
は参照を比較し、実際の文字列は比較しません。 new String(somestring).intern()
を使用してすべての文字列を作成した場合は、==
演算子を使用して2つの文字列を比較できます。それ以外の場合は、equals()またはcompareToメソッドしか使用できません。
Objectにはブール値を返すメソッド.equals()
が含まれているので、すべてのオブジェクトに.equals()
メソッドがあることが保証されています。さらに定義を定義する必要がある場合にこのメソッドをオーバーライドするのはサブクラスの仕事です。それがなければ(すなわち==
を使って)、メモリアドレスだけが2つのオブジェクト間で等しいかどうかチェックされます。 Stringはこの.equals()
メソッドをオーバーライドし、メモリアドレスを使用する代わりに、文字レベルで文字列の比較が等しいかどうかを返します。
重要な注意点は、文字列は1つの一括プールに格納されるため、文字列が作成されると、同じアドレスのプログラムに永久に格納されることです。文字列は変わらず、不変です。これが、大量の文字列処理を行う必要がある場合に、通常の文字列連結を使用することをお勧めしない理由です。代わりに、提供されているStringBuilder
クラスを使用します。この文字列へのポインタは変更される可能性があることを忘れないでください。2つのポインタが同じであるかどうかを調べたい場合は、==
を使用するのがよいでしょう。文字列自体はしません。
Javaでは、 “ ==” 演算子を使用して2つのオブジェクトを比較するときに、オブジェクトがメモリ内の同じ場所を参照しているかどうかを確認します。つまり、2つのオブジェクト名が基本的に同じメモリ位置を参照しているかどうかを確認します。
JavaのStringクラスは、実際にはObjectクラスのデフォルトのequals()実装をオーバーライドします。また、メソッドは、メモリ内の位置ではなく文字列の値のみをチェックするようにオーバーライドします。つまり、equals()メソッドを呼び出して2つのStringオブジェクトを比較すると、実際の文字シーケンスが等しい限り、両方のオブジェクトは等しいと見なされます。
==
演算子は、2つの文字列がまったく同じオブジェクトかどうかを調べます。
.equals()
メソッドは、2つの文字列が同じ値を持つかどうかを調べます。