Index
以下のようにフルーツの名前と値段を保持しているクラスがあります。
1 2 3 4 5 6 7 8 9 |
class Fruits { private final String m_name; private final Integer m_price; Fruits (final String name, final Integer price) { m_name = name; m_price = price; } } |
そのクラスのListが2つあります。
1 2 3 4 5 6 7 8 9 |
List<Fruits> fruitsList = new ArrayList<>(); fruitsList .add(new Fruits("orange",100)); fruitsList .add(new Fruits("peach",200)); fruitsList .add(new Fruits("dragonFruits",300)); List<Fruits> fruitsList2 = new ArrayList<>(); fruitsList .add(new Fruits("orange",100)); fruitsList .add(new Fruits("peach",200)); fruitsList .add(new Fruits("dragonFruits",300)); |
以下のように2つのリストの比較をしようとするとfalseが返ってきます。
1 |
Objects.equals(fruitsList,fruitsList2)//false |
リストの中身は同じはずなのにおかしい….
以下のようにプリミティブ型のリストの場合はちゃんとtrueが返ってくる
1 2 3 4 5 6 7 8 9 10 |
List<Integer> intList = new ArrayList<>(); intList.add(1); intList.add(2); intList.add(3); List<Integer> intList2 = new ArrayList<>(); intList2.add(1); intList2.add(2); intList2.add(3); Objects.equals(intList,intList2);//true |
結論から言うとequals,hashcodeをオーバーライドする必要があります。
実装は以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class Fruits { private final String m_name; private final Integer m_price; Fruits (final String name, final Integer price) { m_name = name; m_price = price; } @Override public boolean equals(Object object) { if(object == this) return true; if(!(object instanceof Fruits)) return false; final Fruits obj = (Fruits)object; return (this.m_name == obj.m_name) && (this.m_price == obj.m_price); } @Override public int hashCode() { final int prime = 31; int result = Integer.hashCode(m_price); result = prime * result + Objects.hashCode(m_name); result = prime * result + Integer.hashCode(m_price); return result; } } |
これで以下のコードでtrueが返ってくるようになります。
1 |
Objects.equals(fruitsList,fruitsList2)//true |
公式のリファレンスはこちら↓
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Object.html#equals-java.lang.Object-
コードについては特に記述することがないので、equalsをオーバライドする時の注意点についてまとめておきます。
①equalsをオーバライドするときは、常にhashCodeをオーバライドする
②あまりにも賢くなろうとしないこと
③equals宣言中のObjectを他の型で置き換えてはいけない
effective java
③については以下のように書いてはいけないということです。
1 |
public boolean equals(Fruits object) |
公式のリファレンスはこちら↓
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Object.html#hashCode–
hashCodeの実装方法は以下の通りです。
- resultという名のint変数を宣言し、クラス内の意味のあるフィールドに対するハッシュコードで初期化する
- クラス内の全ての意味のあるフィールドfに対して[result = 31 * result + Type.hashCode()]を行う
サンプルコードでみるとこんな感じ
1 2 3 4 5 6 7 |
public int hashCode() { final int prime = 31; int result = Integer.hashCode(m_price);//① result = prime * result + Objects.hashCode(m_name);//② result = prime * result + Integer.hashCode(m_price);//② return result; } |
なぜ31なのかというと素数だからだそうです。(伝統的にそうらしい)
Effective Javaの項目10,11を参考に実装をしました。
以下のサイトもかなり参考にさせていただきました。