equals()とhashcode()について


1、新しいStudent.JAvaは、3つのfieldと、対応するget、setメソッドを含む.
package t;

public class Student{
	
	private String id;
	private String name;
	private int age;

	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}	
}

 
2、equals()メソッドを書き換えずにテストを行う.
package t;

public class Test2 {

	public static void main(String[] args){
		
		Student s1 = new Student();
		s1.setId("001");
		
		Student s2 = new Student();
		s2.setId("001");
		
		System.out.println(s1.equals(s2));
	}
}

 
このとき、実行結果はfalseです.
equalsメソッドを書き換えない場合は、親のequalsメソッドがデフォルトで使用されますが、親オブジェクトのequals()メソッドは次のようになります.
 public boolean equals(Object obj) {
	return (this == obj);
    }

すなわち,Objectでequals比較を実行する場合,実際には2等号で比較され,実質的に比較された2つのオブジェクトが同一のオブジェクトであるか否かは,s 1とs 2がそれぞれnewで出てきた2つのオブジェクトであるため,2等号は成立しないため,出力結果はfalseである.
 
3.Studioでequals()メソッドを書き換える.
@Override
	public boolean equals(Object anObject) {
		if (this == anObject) {
		    return true;
		}
		if (anObject instanceof Student) {
			Student anotherStudent = (Student)anObject;
			
			// 2 , 2 。
			return this.getId().equals(anotherStudent.getId());
		}
		return false;    
	}

   
この時点でテストを行い、結果はtrueです.
 
4、equals()を書き換え、hashcode()を書き換えない
 
テストコード:
package t;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Test2 {

	public static void main(String[] args){
		
		Student s1 = new Student();
		s1.setId("001");
		
		Student s2 = new Student();
		s2.setId("001");
		
		// HashSet 
		Set<Student> set = new HashSet<Student>();
		set.add(s1);
		System.out.println(set.contains(s2));

		// HashMap 
		Map<Student, Student> map = new HashMap<Student, Student>();
		map.put(s1, s1);
		System.out.println(map.containsKey(s2));
		System.out.println(map.containsValue(s2));
	}
}

 
実行結果:
falsefalsetrue 
 
5、equals()を書き換え、hashcode()を書き換える.
 
	@Override
	public int hashCode() {	
		return this.id.hashcode();
	}

 
出力結果
truetruetrue
 
以上、equals()を書き換えるにはhashcode()を同時に書き換える必要があります.そうしないと、hashセットで予想と一致しない結果が発生します.
 
補足:1、Stringがequals()を直接使用して2つのStringオブジェクトの値が等しいかどうかを比較できるのは、Stringクラスでequals()メソッドが書き換えられているからです.
 
 /**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    public boolean equals(Object anObject) {
	if (this == anObject) {
	    return true;
	}
	if (anObject instanceof String) {
	    String anotherString = (String)anObject;
	    int n = count;
	    if (n == anotherString.count) {
		char v1[] = value;
		char v2[] = anotherString.value;
		int i = offset;
		int j = anotherString.offset;
		while (n-- != 0) {
		    if (v1[i++] != v2[j++])
			return false;
		}
		return true;
	    }
	}
	return false;
    }

 
 
2、equals()が等しい2つのオブジェクトは、hashcode()も等しいことを保証しなければならない.そうしないとjavaのhash集合クラスに問題が発生する.
3、equals()が等しくない2つのオブジェクトは、hashcode()が等しい可能性があります(ハッシュ生成時に衝突によるもの).
4、HashMapではcontainsKey(Object obj)、get(Object obj)があり、mapに指定されたkeyが含まれているか否かを判断したり、keyに基づいてvalueをクエリした場合、keyが等しいか否かを判断するルールはhashcodeが等しく、equalsがtrueを返す.
hashmapクラスget(Object obj)実装の場合:
  public V get(Object paramObject)
  {
    if (paramObject == null)
      return getForNullKey();
    int i = hash(paramObject.hashCode());
    for (Entry localEntry = this.table[indexFor(i, this.table.length)]; localEntry != null; localEntry = localEntry.next)
    {
      Object localObject;
      if ((localEntry.hash == i) && (((localObject = localEntry.key) == paramObject) || (paramObject.equals(localObject))))
        return localEntry.value;
    }
    return null;
  }

5、hashcodeは主にHashtable、HashMap、HashSet、LinkedHashMapなどのhash集合クラスのために存在し、hash集合クラスはより効率的な(ハッシュアルゴリズム)クエリーと記憶を行うことができる. 
  http://huangqiqing123.iteye.com/blog/1462404