shokosブログ

プログラミング

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));