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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

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

Q&A

解決済

4回答

2485閲覧

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

sobue

総合スコア329

Java

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

0グッド

0クリップ

投稿2017/03/01 13:36

java

1package test; 2 3public class Sample { 4 5 private int num; 6 7 private String name; 8 9 public Sample(int num, String name) { 10 // TODO 自動生成されたコンストラクター・スタブ 11 12 this.num = num; 13 this.name = name; 14 15 } 16 public boolean equals(Object obj){ 17 if(obj == null){ 18 return false; 19 } 20 if(obj instanceof Sample){ 21 Sample s = (Sample) obj; 22 return s.num == this.num; 23 } 24 return false; 25 } 26 27} 28

上記のクラスが前提で

java

1 Sample a = new Sample(10,"a"); 2 3 Sample b = new Sample(10,"b"); 4 5 System.out.println(a.equals(b));

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

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

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

投稿2017/03/01 13:56

編集2017/03/01 13:57
swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sobue

2017/03/04 03:52

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

0

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

==

田中さん == 田中さん

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

equals

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

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

投稿2017/03/02 01:41

masaya_ohashi

総合スコア9206

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

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

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

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

Java

1package test; 2 3import java.util.HashMap; 4import java.util.Map; 5 6public class MutableSample { 7 8 private int num; 9 private String name; 10 11 public MutableSample(int num, String name) { 12 this.num = num; 13 this.name = name; 14 } 15 16 @Override 17 public boolean equals(Object obj){ 18 if(!(obj instanceof MutableSample)){ 19 return false; 20 } 21 MutableSample s = (MutableSample) obj; 22 return s.num == this.num; 23 } 24 25 @Override 26 public int hashCode(){ 27 return this.num; 28 } 29 30 public void setNum(int num) { 31 this.num = num; // 変更可能 32 } 33 public int getNum() { 34 return this.num; 35 } 36}

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

実行例

Java

1 public static void main(String[] args) { 2 MutableSample a = new MutableSample(10,"a"); 3 MutableSample b = new MutableSample(10,"b"); 4 System.out.println("a == b : " + a.equals(b)); 5 6 Map<MutableSample,MutableSample> map = new HashMap<>(); 7 map.put(a,a); 8 System.out.println("map.containsKey(b) : " + map.containsKey(b)); 9 a.setNum(20); 10 System.out.println("map.containsKey(b) : " + map.containsKey(b)); 11 }

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

結論

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

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

参考
edx: Software Construction in Java

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

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

Java

1package test; 2 3public class ImmutableSample { 4 5 private final int num; 6 private final String name; 7 8 public ImmutableSample(int num, String name) { 9 this.num = num; 10 this.name = name; 11 } 12 13 @Override 14 public boolean equals(Object obj){ 15 if(!(obj instanceof ImmutableSample)){ 16 return false; 17 } 18 ImmutableSample s = (ImmutableSample) obj; 19 return (s.num == this.num && s.name.equals(this.name)); 20 } 21 22 @Override 23 public int hashCode(){ 24 return (this.num + this.name.hashCode()); 25 } 26 27}

投稿2017/03/01 21:52

編集2017/03/01 22:41
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2017/03/02 00:04

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

2017/03/02 00:14

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

2017/03/02 01:13

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

退会済みユーザー

2017/03/02 01:18

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

2017/03/02 01:19

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

退会済みユーザー

2017/03/02 01:34

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

2017/03/02 01:38

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

退会済みユーザー

2017/03/02 02:06

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

2017/03/02 02:09

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

退会済みユーザー

2017/03/02 04:56

今さら言うのもあれですが、edxのコース6.005.1xでは、次のように解説しています。 ・HashMapに格納するキーオブジェクトがimmutableなら、キーフィールドが不変なので、キーオブジェクトのequals()/hashCode()をオーバーライドできる。 ・HashMapに格納するキーオブジェクトがmutableで、キーフィールドが変更可能なら、キーオブジェクトのequals()/hashCode()をオーバーライドせず、基底クラスObjectのequals()/hashCode()をそのまま使用すべきである。この場合、言うまでもなくObject.equals()内部では==判定が行われ、インスタンスが同一の場合にのみ等しい。 と言うわけで、ここでequals()と== の使い分けがでてくるのです。質問の本質からは外れていますね。
guest

0

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

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

投稿2017/03/01 14:19

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KiyoshiMotoki

2017/03/02 00: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 02:15

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問