HashCode 재정의
규약
equals를 재정의하면 hashCode도 재정의해야 한다. Object 명세에서 발췌한 규약을 보자.
- equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 그 객체의 hashCode 메소드는 몇 번을 호출해도 일관되게 같은 값을 반환해야 한다.
- equals가 두 객체가 같다고 판단한다면 hashCode도 같은 값을 반환해야 한다.
- equals가 두 객체가 다르다고 판단했더라도 hashCode가 무조건 다를 필요는 없다.
주의점
- equals에서 사용하지 않은 필드는 ‘반드시’ hashCode에서 제외해야만 한다. 성능 높인답시고 제외시키면 안된다.
- hashCode를 lazy로 설정하려면 threadSafe까지 고려해야 한다.
- hashCode 대상을 공개하지 않는 것이 좋다. 그래야 추후 계산 방식을 바꿀 수도 있다.
정의 방법
- int 필드(result)를 하나 생성한다.
- 1에서 만든 필드에
- Type.hashCode()를 할당한다.
- 참조 타입이면 표준형(canonical representation)을 만들어 호출한다.
- 필드가 배열이면 핵심 원소를 각각 필드처럼 다룬다. 혹은 Arrays.hashCode를 사용한다.
- result = 31 * result + Type.hashCode()를 필드마다 반복한다.
31인 이유는 홀수이면서 소수이기 때문에 전통적으로 썻다고 한다. 위 예시를 풀어보면 아래와 같다.
@Override
public int hashCode () {
int result = Short.hashCode(a);
result = 31 * result + Integer.hashCode(b);
result = 31 * result + Double.hashCode(c);
return result;
}