맥락은 다르지만 Effective C++의 연산자 오버로딩 구현 처럼
java에서는 override를 준수해야 하는 메서드 조합들이 있다.
그것들은 equals, hashCode toString, clone, finalize 이다.
이것을 effective java에서는 general contracts 라고 표현하는데
대충 공통 메서드 가이드 라인이라고 보면 될것 같다.(책에서는 equals, hashCode, toString에 중점을 두었다.)
equals의 구현 방향 및 소스는 effective java 및 JavaSE의 박스화 기본형(boxed primitive)을 참고하자(Byte, Integer...등)
책에서는 equals 메서드를 오버라이드 할 때 hashCode메서드를 항상 같이 오버라이드 하길 권장 하고 있다.
여기서 hashCode는 동일한 객체의 경우 객체들은 같은 해시 코드를 가져야 한다.(디테일한 규약들은 API 문서 명세 및 책 참고)
또한 hashCode 구현 방법에 따라 컬렉션의 성능이 좌우된다고 한다.
아래는 Effective Java에서 설명하는 hashCode 구현 방법이다.
- 예를 들어, 17과 같이 0이 아닌 어떤 상수 값을 result라는 int 변수에 저장한다.
- 우리 객체의 각 주요 필드(equals 메소드에서 비교하는) f에 대해 다음을 수행한다.
- 각 필드에 대한 int 타입의 해시 코드 c를 다음과 같이 산출한다.
- 필드 f가 boolean 타입이면, (f ? 1 : 0).
- 필드 f가 byte, char, short, int 타입이면, (int)f
- 필드 f가 long 타입이면, (int) (f ^ (f >>> 32)).
- 필드 f가 float 타입이면, Float.floatToIntBits(f).
- 필드 f가 double 타입이면, Double.doubleToLongBits(f)를 실행한 후 반환된 long 타입의 값을 앞의 2.a.iii처럼 처리하여 해시 코드 값을 구한다.
- 필드 f가 객체 참조일 경우는, 현재(equals 메소드가 호출된) 객체의 equlas 메서드에서 그 필드를 비교하기 위해 f가 참조하는 객체의 equals 메서드를 재귀적으로 호출. 그러면 그 객체의 필드에 대해 hashCode 메서드도 재귀적으로 자동 호출됨. f값이 null이면 0을 반환 그 외 디테일은 생략..(책 참조)
- 필드 f가 배열이라면 배열의 각 요소를 별개의 필드처럼 처리한다. 그리고 2.b 수식을 적용, 합을 구한다. 만일 배열 필드의 모든 요소를 처리해야 한다면 Array.hashCode 중 하나를 사용
- 앞의 2.a 단계에서 구한 해시 코드 c를 result에 합계한다.(result = 31 * result + c;)
- result를 반환.
- 검토, 테스트, 실행 검증등..
위 소스는 책의 PhoneNumber클래스의 hashCode메서드 샘플 예제 이다.
출처 : Effective Java