web-dev-qa-db-ja.com

JavaのassertEqualsメソッドは信頼できますか?

2つのStringsを比較するとき、==にはいくつかの問題があることを私は知っています。 String.equals()がより良いアプローチであるようです。さて、私はJUnitテストをしています、そして私の志向はassertEquals(str1, str2)を使うことです。これは、2つの文字列に同じ内容が含まれていると主張するための信頼できる方法ですか?私はassertTrue(str1.equals(str2))を使用しますが、その場合、期待値と実際の値が失敗したことを確認してもメリットはありません。

関連するメモで、誰かがstr1 == str2に関する問題を明白に説明しているページまたはスレッドへのリンクを持っていますか?

190
DivideByHero

JavaでStringsを比較するときは、常に常に.equals()を使用する必要があります。

JUnitは.equals()メソッドを呼び出して、メソッドassertEquals(Object o1, Object o2)の等価性を判断します。

だから、あなたはassertEquals(string1, string2)を使って間違いなく安全です。 (StringsはObjectsなので)

これは==.equals()の違いのいくつかに関する素晴らしいStackoverflowの質問 へのリンクです。

263
jjnguy

assertEqualsは、比較にequalsメソッドを使用します。 ==演算子を使用する別のアサートassertSameがあります。

==が文字列と一緒に使用されるべきでない理由を理解するためには、==が何をするのか理解する必要があります:それはアイデンティティチェックをします。つまり、a == bは、ab同じオブジェクトを参照しているかどうかを確認します。これは言語に組み込まれており、その動作は異なるクラスによって変更することはできません。一方、equalsメソッドはクラスでオーバーライドできます。 (Objectクラスの)デフォルトの動作は==演算子を使用してアイデンティティチェックを行うことですが、Stringを含む多くのクラスはそれをオーバーライドして代わりに「等価」チェックを行います。 Stringの場合、abが同じオブジェクトを参照しているかどうかを確認する代わりに、a.equals(b)は参照しているオブジェクトが両方ともまったく同じ文字を含む文字列であるかどうかを確認します。

同じような時:それぞれのStringオブジェクトは何かが書かれた一枚の紙であると想像してください。 "Foo"が書かれた2枚の紙と、 "Bar"が書かれた別の紙があるとしましょう。最初の2枚の紙を取り、それらを比較するために==を使用すると、それは本質的に「これらは同じ紙ですか?」と尋ねるのでfalseを返します。紙に書かれていることを見る必要さえありません。 2枚の紙を(同じ紙を2回ではなく)2枚渡しているということは、falseが返されることを意味します。しかし、equalsを使用すると、equalsメソッドは2枚の紙を読み、それらが同じこと( "Foo")を言っていることがわかるので、trueを返します。

文字列と混乱してしまうのは、Javaには「内部」文字列という概念があり、これが(事実上)コード内の任意の文字列リテラルに対して自動的に実行されることです。つまり、コード内に2つの同等の文字列リテラルがある場合(それらが異なるクラスに属していても)、実際には両方とも同じStringオブジェクトを参照します。これにより、==演算子はtrueを予想以上に頻繁に返します。

30

一言で言えば - 同じ文字を含むが異なるオブジェクト(異なるメモリ位置にある)である2つのStringオブジェクトを持つことができます。 ==演算子は2つの参照が同じオブジェクト(メモリ位置)を指していることを確認しますが、equals()メソッドは文字が同じかどうかを確認します。

通常、2つの文字列が同じ文字を含んでいるかどうかを確認することに興味があります。それらが同じメモリ位置を指しているかどうかではありません。

7
Ken Liu

はい、それはテストのためにいつも使われています。このような比較のためにテストフレームワークが.equals()を使用する可能性が非常に高いです。

以下は「文字列の等価性の誤り」を説明するリンクです。基本的に、Javaの文字列はオブジェクトであり、オブジェクトの等価性を比較すると、通常、コンテンツではなくメモリアドレスに基づいて比較されます。このため、内容が同一であっても、2つの文字列が同じアドレスを占有することはありません。したがって、印刷時に同じに見えても、正しく一致しません。

http://blog.enrii.com/2006/03/15/Java-string-equality-common-mistake/

3
Soviut
public class StringEqualityTest extends TestCase {
    public void testEquality() throws Exception {
        String a = "abcde";
        String b = new String(a);
        assertTrue(a.equals(b));
        assertFalse(a == b);
        assertEquals(a, b);
    }
}
3
Carl Manaster

JUnitのassertEquals(obj1, obj2)は実際にobj1.equals(obj2)を呼び出します。

obj1 == obj2を実行するassertSame(obj1, obj2)もあります(つまり、obj1obj2同じインスタンスを参照していることを確認します)、これは避けようとしていることです。

だから大丈夫です。

3
Jack Leow

"==演算子は、2つのObjectsがまったく同じObjectであるかどうかを確認します。"

http://leepoint.net/notes-Java/data/strings/12stringcomparison.html

StringはJavaのObjectなので、そのカテゴリの比較規則に分類されます。

0