Book/이펙티브 자바

Item11 - equals를 재정의하려거든 hashCode도 재정의하라(2)

발망생 2023. 11. 22. 23:25

 

 

좋은 해시 함수라면 서로 다른 인스턴스에 다른 해시코드를 반환한다. 이상 적인 해시 함수는 서로 다른 인스턴스들을 32bit 정수 범위에 균일하게 분배해야 한다. 다음은 좋은 hashCode를 작성하는 간단한 요령이다.

 

public final class PhoneNumber {
    private final short areaCode, prefix, lineNum;

    public PhoneNumber(int areaCode, int prefix, int lineNum) {
        this.areaCode = rangeCheck(areaCode, 999, "area code");
        this.prefix   = rangeCheck(prefix,   999, "prefix");
        this.lineNum  = rangeCheck(lineNum, 9999, "line num");
    } 
 
 	... 코드 생략
    
 	// 코드 11-2 전형적인 hashCode 메서드 (70쪽)
    @Override public int hashCode() {
    	//기본 타입 필드라면 Type.hashCode(f)
        int result = Short.hashCode(areaCode);
        result = 31 * result + Short.hashCode(prefix);
        result = 31 * result + Short.hashCode(lineNum);
        return result;
    }
}

 

파생 필드는 해시코드 계산에서 제외해도 된다. 도한 equals 비교에 사용되지 않는 필드는 '반드시' 제외해야 한다.(규약 두 번째)

 

클래스가 불변이고 해시코드를 계산하는 비용이 크다면, 매번 새로 계산하기 보다는 캐싱하는 방식을 고려해야 한다. 해시의 키로 사용되지 않는 경우라면 hashCode가 지연 초기화 전략을 사용할 수 있다.(스레드 세이프하게)

 

    private int hashCode; // 자동으로 0으로 초기화된다.

    @Override public int hashCode() {
        int result = hashCode;
        if (result == 0) {
            result = Short.hashCode(areaCode);
            result = 31 * result + Short.hashCode(prefix);
            result = 31 * result + Short.hashCode(lineNum);
            hashCode = result;
        }
        return result;
    }