質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.53%

  • Java

    13742questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

javaの==とequalsの違いについて

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 605

sobue

score 164

package test;

public class Sample {

    private int num;

    private String name;

    public Sample(int num, String name) {
        // TODO 自動生成されたコンストラクター・スタブ

        this.num = num;
        this.name = name;

        }
    public boolean equals(Object obj){
        if(obj == null){
            return false;
        }
        if(obj instanceof Sample){
            Sample s = (Sample) obj;
            return s.num == this.num;
        }
        return false;
    }

}


上記のクラスが前提で

        Sample a = new Sample(10,"a");

        Sample b = new Sample(10,"b");

        System.out.println(a.equals(b));


の処理をするとtrueが返ってきますが、どのような時に「==」でどんな時に「equals」を使用していいがわかりません。
使い分けはどのようにしたらいいのでしょうか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+1

参照型ではequals
プリミティブ型では==

ただし参照型でも「同じオブジェクトを指す」という条件にしたいなら==

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/04 12:52

    いつも、ありがとうございます。

    キャンセル

0

Sampleオブジェクトの同一性をnumを使って判定したい場合に、equalsメソッドをオーバーライドします。
つまり、アプリケーションを設計するうえで、Sampleのインスタンスは、numが等しいなら意味的に等しい場合。

equals()をオーバーライドする場合は、hshCode()もオーバーライドしなければなりません。
a.equals(b) ならば a.hshCode() == b.hashCode() でなければならない。
これは、ハッシュマップのキーにSampleを使用することがあるからです。

ただし、ハッシュマップのキーにSampleを使用するなら、注意点があります。

Sampleのnumがインスタンス生成後に変更されるなら、equals()の比較に使用できない。
理由は、HashMapに格納した後、aの値を変更すると取り出せなくなるから。
例を示します。

package test;

import java.util.HashMap;
import java.util.Map;

public class MutableSample {

    private int num;
    private String name;

    public MutableSample(int num, String name) {
        this.num = num;
        this.name = name;
    }

    @Override
    public boolean equals(Object obj){
        if(!(obj instanceof MutableSample)){
            return false;
        }
        MutableSample s = (MutableSample) obj;
        return s.num == this.num;
    }

    @Override
    public int hashCode(){
        return this.num;
    }

    public void setNum(int num) {
        this.num = num; // 変更可能
    }   
    public int getNum() {
        return this.num;
    }
}


setterを用意してnumの値を変更可能にしました。

実行例

    public static void main(String[] args) {
        MutableSample a = new MutableSample(10,"a");
        MutableSample b = new MutableSample(10,"b");
        System.out.println("a == b : " + a.equals(b));

        Map<MutableSample,MutableSample> map = new HashMap<>();
        map.put(a,a);
        System.out.println("map.containsKey(b) : " + map.containsKey(b));
        a.setNum(20);
        System.out.println("map.containsKey(b) : " + map.containsKey(b));
    }

インスタンスaをマップに格納したのち、aのnumの値を変更しました。
aはマップの中から取り出せなくなります。

結論

equlas()内で、比較に使用するフィールドの値が変更可能かどうか?
インスタンスを生成してから変更されることがないなら、equals()で比較しても良い。
インスタンス生成後に変更されるなら、equals()の比較に使用できない。

equals()をオーバーライドするならhashCode()もオーバーライドしなければならない。

参考
edx: Software Construction in Java

###追記(意味的に同じにしたければ)

numとnameがともに等しければ、おなじSampleオブジェクトだと判定する、という回答が抜けていました。

package test;

public class ImmutableSample {

    private final int num;
    private final String name;

    public ImmutableSample(int num, String name) {
        this.num = num;
        this.name = name;
    }

    @Override
    public boolean equals(Object obj){
        if(!(obj instanceof ImmutableSample)){
            return false;
        }
        ImmutableSample s = (ImmutableSample) obj;
        return (s.num == this.num && s.name.equals(this.name));
    }

    @Override
    public int hashCode(){
        return (this.num + this.name.hashCode());
    } 

}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/02 09:04

    質問内容の本質からは若干外れますが、せっかくのコード例なのでコンストラクターで
    this.name = Objects.requireNonNull(name);
    としておくかequals/hashCodeにnameがnullの場合の配慮をしておくほうがベターだと思います。

    キャンセル

  • 2017/03/02 09:14

    Map云々の話は、「Mapのキーとして使うとき、内容変更すると正しくMapが動作しないよ」という話であり、「equals()で比較できない」というわけではありません。
    keySet()やentrySet()で取り出していって探す方法なら見つけることができます。

    キャンセル

  • 2017/03/02 10:13

    > keySet()やentrySet()で取り出していって探す方法なら見つけることができます
    「Mapのキーの内容を変更しても取り出せるから問題ない」と示唆しているわけではないと思いますがそうであると誤解されてしまう恐れがあるのでは?キーを変更したからkeySetで取り出すというのはkeySetの本来の目的とは異なる裏技的な使い方であり設計が破綻している恐れ大だと思います。むしろ「キーに使うと問題が起こることを意識しつつmutableな実装も選択可能」とだけ言った方がよいと思います。

    キャンセル

  • 2017/03/02 10:18

    KSwordOfHasteさん、おっしゃるとおりです。NULLの対応とHASH_INCRIMENTを乗ずるなどの対応があれば万全でしょう。
    swordoneさん、おっしゃるとおり「純粋にequals()の機能だけみれば比較できる」が正しいです。sobueさんの質問の意図に答えるなら「equals()の中でnumとnameがともに等しい判定コードを書いてください」で済むのかもしれません。
    しかし、そのオブジェクトのライフサイクル(保守も含めて)で、HashMapのキーとして使われることが想定されるなら、equals()/hashCode()の両方を記述すること、比較に使用するフィールドはimmutableであること。
    ついでに、a.equals(b) ならば a.hshCode() == b.hashCode() でなければならない。は、逆は成り立ちません。

    キャンセル

  • 2017/03/02 10:19

    もちろんその通りです。しかし内部情報が変化するからequalsで比較できないという話はおかしいので突っ込ませてもらいました。

    キャンセル

  • 2017/03/02 10:34

    「Sampleのnumがインスタンス生成後に変更されるなら、equals()の比較に使用できない。 」と表現すべきでなかった。これからは改めます。

    キャンセル

  • 2017/03/02 10:38

    いや、equals()の比較はできるんですって。
    HashMapなどの動作が正常にいかなくなるだけであって。

    キャンセル

  • 2017/03/02 11:06

    そのとおり、全て理解しています。「表現すべきでなかった」と書いたのは「equals()の比較はできる」という意図です。HashMap、HashSet、などがうまくいかなくなる「だけ」といのも理解しています。

    キャンセル

  • 2017/03/02 11:09

    すいません、鍵括弧のあとを勝手に「すべきだった」と読みました。失礼しました。

    キャンセル

  • 2017/03/02 13:56

    今さら言うのもあれですが、edxのコース6.005.1xでは、次のように解説しています。

    ・HashMapに格納するキーオブジェクトがimmutableなら、キーフィールドが不変なので、キーオブジェクトのequals()/hashCode()をオーバーライドできる。

    ・HashMapに格納するキーオブジェクトがmutableで、キーフィールドが変更可能なら、キーオブジェクトのequals()/hashCode()をオーバーライドせず、基底クラスObjectのequals()/hashCode()をそのまま使用すべきである。この場合、言うまでもなくObject.equals()内部では==判定が行われ、インスタンスが同一の場合にのみ等しい。

    と言うわけで、ここでequals()と== の使い分けがでてくるのです。質問の本質からは外れていますね。

    キャンセル

0

例えばここに田中さんと田中さんがいたとします。

 ==

田中さん == 田中さん


とした場合、いくら名前が同じでも別人なのでこれはfalseとなります。==という比較は「実体そのものが同一であること」の判定です。

 equals

田中さん.equals(田中さん)


とした場合、equals処理の中が「同名であるか」の判断処理であれば、これはtrueとなります。equalsという比較は「equalsの処理の中身で決まる」判定です。Stringであれば「同じ事が書いてあればOK」ですし、Integerであれば「同じ数字であればOK」です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

上記のSampleクラス同士の比較の場合

aとbのハッシュコードが同一(同一インスタンス)であるかどうか確かめる時は==を用いる
aとbの持つnumが一致するかどうか確かめる場合は.equals()を用いる

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/02 09:52

    「ハッシュコードが同一」 <=> 「同一インスタンス」
    ではありませんよ。

    ハッシュコードの計算方法によっては、異なるインスタンスが同じハッシュコードを返すこともあり得ますし、
    hashCode() メソッドを誤った方法でオーバーライドすれば、同一のインスタンスが毎回、異なるハッシュコードを返すようにもできます。

    あくまでも、オブジェクトに対する '==' 演算子は
    「参照が同一か?」
    を見ているのであって、
    「ハッシュコードが同一か?」
    を見ているわけではありません。

    ■テストコード
    --------------------------------------------
    public class Main {
      public static void main(String[] args) {
        Sample1 s1a = new Sample1();
        Sample1 s1b = new Sample1();

        System.out.println(s1a);
        System.out.println(s1b);
        System.out.println(s1a == s1b);

        System.out.println();

        Sample2 s2 = new Sample2();

        System.out.println(s2);
        System.out.println(s2);
        System.out.println(s2 == s2);
      }
    }

    class Sample1 {
      @Override
      public int hashCode() {
        return 1; // 全てのインスタンスが同じ値を返す。
      }
    }

    class Sample2 {
      private int i = 0;

      @Override
      public int hashCode() {
        return i++; // 毎回、異なる値を返す。
      }
    }
    --------------------------------------------

    ■実行結果
    --------------------------------------------
    Sample1@1
    Sample1@1
    false

    Sample2@0
    Sample2@1
    true
    --------------------------------------------

    キャンセル

  • 2017/03/02 11:15

    実行確認しました
    そのようです

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.53%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Java

    13742questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。