Effect Java 제2판(Joshua Bloch / Addison Wesley) 을 공부하고 정리한 내용 입니다.

9. equals메소드를 오버라이드 할 때는 hashCode 메소드도 항상 같이 오버라이드 하자.

Object.hashcode 메소드 명세서에서 가져 온 계약 사항은 다음과 같다.

  • 애플리케이션 실행 중에 같은 객체에 대해 한 번 이상 호출되더라도 hashCode 메소드는 같은 정수를 일관성 있게 반환해야 한다(equals 메소드에서 비교하는 객체의 값이 변경되지 않는다면).
    단, 이 정수 값은 애플리케이션이 매번 다시 실행될 때마다 일관되게 같을 필요는 없다.
  • equals(Object) 메소드 호출 결과 두 객체가 동일하다면, 두 객체 각각에 대해 hashCode 메소드를 호출했을 때 같은 정수 값이 나와야 한다.
  • equals(Object) 메소드 호출 결과 두 객체가 다르다고 해서 두 객체 각각에 대해 hashCode메소드를 호출했을 때 반드시 다른 정수 값이 나올 필요는 없다. 그러나 같지 않은 객체들에 대해 hashCode 메소드에서 서로 다른 정수 값을 반환하면, 이 메소드를 사용하는 해시 컬렉션들(HashMap, HashSet, Hashtable등)의 성능을 향상시킬 수 있음을 알아야 한다.

hashCode의 오버라이딩에 실패했을 때 위배되는 주요 조항은 두 번째 것으로써, 동일한 객체들은 같은 해시 코드 값을 가져야 한다는 것이다.

 
	// 최악의 hashCode 메소드 - 절대 이렇게 사용하지 말 것!
	@Override
	public int hashCode() {
		return 42;
	}

 

HashCode 를 만드는 간단한 방법

  1. 예를 들어, 17과 같이  0이 아닌 어떤 상수 값을 result라는 int 변수에 저장한다.
  2. 우리 객체의 각 주요 필드(equals 메소드에서 비교하는) f에 대해 다음을 수행한다.
    1. 각 필드에 대한 int 타입의 해시 코드 c를 다음과 같이 산출한다.
      1. 필드 f가 boolean 타입이면, (f ? 1 : 0)
      2. 필드 f가 byte, char, short, int 타입이면 (int)f
      3. 필드 f가 long 타입이면, (int)(f ^ (f >>> 32)).
      4. 필드 f가 float 타입이면 Float.floatToIntBits(f)
      5. 필드 f가 double 타입이면 Double.doubleToLongBits(f)를 실행한 후 반환된 long 타입의 값을 앞의  III 처럼 처리하여 해시 코드 값을 구한다.
      6. 필드 f가 객체 참조일 경우는, 현재(equals 메소드가 호출된) 객체의 equals 메소드에서 그 필드를 비교하기 위해 f가 참조하는 객체의 equals 메소드를 재귀적으로 호출한다. 그러면 그 객체의 필드에 대해 hashCode 메소드도 재귀적으로 자동 호출된다. 만일 더 복잡한 비교(객체의 여러 필드를 비교하거나, 필드의 복잡한 연산과 같은)가 필요하다면, 필드의 "표준 형식"을 만들어 처리하고 그 표준 형식에 대해 hashCode 메소드를 호출한다. 만일 필드 f의 값이 null이면, 0을 반환한다(또는 다른 어떤 상수 값도 가능하지만 관례적으로 0을 사용한다.)
      7. 필드 f가 배열이라면 배열의 각 요소를 별개의 필드처럼 처리한다. 즉, 위의 규칙들을 적용하여 처리를 해야 할 요소 각각의 해시 코드 값을 산출한다. 그리고 바로 밑의 2.2 수식을 적용하여 그값들의 합을 구한다. 만일 배열 필드의 모든 요소를 처리해야 한다면 자바 1.5 버전에 새로 추가되어 오버로딩 된 Arrays.hashCode 메소드들 중 하나를 사용할 수 있다.
    2. 앞의 2.1 단계에서 구한 코드 c를 result에 합계한다.
      result = 31 * result + c;
    3. result 를 반환한다.
    4. hashCode 메소드 작성이 끝나면 동일한 인스턴스들이 같은 값의 해시 코드를 갖는지 검토하자. 그리고 단위 테스트를 작성하여 잘 실행되는지 검증하자.

 

 
	// 어떤 클래스의 세 개의 중요 필드가 있고, 모두 short 타입 일 경우
	@Override
	public int hashCode() {
		int result = 17;
		result = 31 * result + areaCode;
		result = 31 * result + prefix;
		result = 31 * result + lineNumber;
		return result;
	}
Posted by outliers
,