equalsやhashCodeの話
たとえばidとnameをもつこんなクラスがあったとして
class Bean { private Long id; private String name; public Bean(Long id, String name) { this.id = id; this.name = name; } public Long getId() { return id; } public String getName() { return name; } }
下記を実行してみると
Bean bean1 = new Bean(1L, "shokos"); Bean bean2 = new Bean(1L, "shokos"); System.out.println(bean1 == bean2); System.out.println(bean1.equals(bean2));
上は別オブジェクトなのでfalseが返ってくるけれど、下は中身いっしょなのでtrueが返ってくると思いこんでいました
ただequalsの中身を見てみるとこういう風になっていて
public boolean equals(Object obj) { return (this == obj); }
中身が一緒だからtrueが返ってくるってするには、BeanクラスでequalsをOver
rideしてそういう実装にしないといけないようです
eclipseはすごいので、Beanクラスで右クリックすればequalsを実装してくれる選択肢がでてくるのだけど、
例えばIDが自動で連番が割り振られて、nameだけで判定したいって時があるかもしれないので、そういう想定をしてマイ実装しました
@Override public boolean equals(Object obj) { if(obj == null || !(obj instanceof Bean)) { return false; } return Bean.class.cast(obj).getName() == this.name; }
これで下記の実行結果がtrueになります
Bean bean1 = new Bean(1L, "shokos"); Bean bean2 = new Bean(2L, "shokos"); System.out.println(bean1.equals(bean2));
ただこれだけだと次の場合はfalseに><
Map<Bean, String> map = new HashMap<Bean, String>(); map.put(bean1, "shokos1"); System.out.println(map.containsKey(bean2));
containsKeyの中身をみると、まずhashCodeをみてそれからequalsを見ていました
オブジェクトを数値として扱ってくれるhashCodeが、実装されていないためfalseになったようです
数値のほうがクイックソートなどが使えて、検索速度が速くて便利だそうです
hashCodeもnameが一致すればおkなようにOverrideしました
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; }
これで下記すべてがtrueになりました!
Bean bean1 = new Bean(1L, "shokos"); Bean bean2 = new Bean(2L, "shokos"); System.out.println(bean1.equals(bean2)); Map<Bean, String> map = new HashMap<Bean, String>(); map.put(bean1, "shokos1"); System.out.println(map.containsKey(bean2));