JAva equalsとhashCode


jdkドキュメントだけを読むと、初心者にとってjavaがなぜこの2つの方法を書き直す必要があるのか理解しにくい.オブジェクト向けの世界では,2つのオブジェクトが等しいか(あるいは論理的に等しいか)をどのように決定するかが解決すべき問題であり,Javaはequal法によって2つのオブジェクトが等しいかどうかを決定する.Javaオブジェクトの作成はスタック上で行われますが、newキーワードでクラスの2つのオブジェクトを作成するとjavaではどのようにして2つのオブジェクトが等しいかどうかを判定しますか?
 
例を挙げます.
class Employee {
	Integer id;
	public void setId(Integer id) {
		this.id = id;
	}
} 

 もしある会社が社員番号が同じであれば同じ社員だと思っていたら(ちょっと不合理ですが、もっと似たような例は思いませんでした).次に、次のコードで従業員が同じ人かどうかを判断します.
        Employee e1 = new Employee();
        Employee e2 = new Employee();
        e1.setId(1);
        e2.setId(1);
        
        System.out.println(e1.equals(e2));

 残念ながら、このコードの出力はfalseです.
このような2人の従業員が同じ従業員であると判定するためにはequalsメソッドを書き換える必要がある.
class Employee {
	Integer id;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
	@Override
	public boolean equals(Object o) {
		if(o == null) {
			return false;
		}
		if (o == this) {
			return true;
		}
		if (getClass() != o.getClass()) {
			return false;
		}
		Employee e = (Employee) o;
		return (this.getId() == e.getId());
	}
}

 
次のテスト方法を実行します.
        Employee e1 = new Employee();
        Employee e2 = new Employee();
        e1.setId(1);
        e2.setId(1);
        
        System.out.println(e1.equals(e2));
         
        Set<Employee> employees = new HashSet<Employee>();
        employees.add(e1);
        employees.add(e2);
        
        System.out.println(employees);
        System.out.println(e1.equals(e2));

 プログラムの実行結果は次のとおりです.
true
[com.shunwang.meteor.example.Employee@dc8569, com.shunwang.meteor.example.Employee@1bab50a]
 
1つ目の実行結果は正しいのですが、2つ目は2つも出力されていて、JavaではSetが重くなるのですが、問題はどこにあるのでしょうか?
元々、JavaではHashSetのストレージに対してHashMapを利用していましたが、HashMapは配列にチェーンテーブルを付けたデータ構造を採用しています(はっきりしない場合はHashMapのソースコードを読んでください.HashMapのストレージ構造を知っていれば、この問題はよく理解できます).HashMapは、まずオブジェクトのhashcodeによって格納位置を計算し(hashが衝突した場合、その位置はチェーンテーブルで衝突を解決する)、要素の値を比較します.上記の問題は、書き換えられていないオブジェクトのhashcodeメソッド(デフォルトではObjectを継承し、デフォルトではオブジェクトのメモリアドレス番号を返します).修正コードは次のとおりです.
class Employee {
	Integer id;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	
	@Override
	public boolean equals(Object o) {
		if(o == null) {
			return false;
		}
		if (o == this) {
			return true;
		}
		if (getClass() != o.getClass()) {
			return false;
		}
		Employee e = (Employee) o;
		return (this.getId() == e.getId());
	}
	
	@Override
	public int hashCode() {
	    final int code = 31;
	    int result = 1;
	    result = code * result + getId();
	    return result;
	}
}

 
実行結果:
true
[com.shunwang.meteor.example.Employee@20]
 
この2つの方法の用途を理解すれば,文章に記述されている様々な「性」を記述すれば理解できる.