回答編集履歴

1 意味的に同じ例を追加

退会済みユーザー

退会済みユーザー

2017/03/02 07:41  投稿

Sampleオブジェクトの同一性をnumを使って判定したい場合に、equalsメソッドをオーバーライドします。
つまり、アプリケーションを設計するうえで、Sampleのインスタンスは、numが等しいなら意味的に等しい場合。
equals()をオーバーライドする場合は、hshCode()もオーバーライドしなければなりません。
a.equals(b) ならば a.hshCode() == b.hashCode() でなければならない。
これは、ハッシュマップのキーにSampleを使用することがあるからです。
ただし、ハッシュマップのキーにSampleを使用するなら、注意点があります。
Sampleのnumがインスタンス生成後に変更されるなら、equals()の比較に使用できない。
理由は、HashMapに格納した後、aの値を変更すると取り出せなくなるから。
例を示します。
```Java
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の値を変更可能にしました。
実行例
```Java
   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
edx: Software Construction in Java
###追記(意味的に同じにしたければ)
---
numとnameがともに等しければ、おなじSampleオブジェクトだと判定する、という回答が抜けていました。
```Java
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());
   }
 
}
```

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る