Equals를 구현했다면 HashCode 또한 반드시 구현해야 한다. 그 이유는 HashMap이나 HashSet과 같은 컬렌션의 원소로 사용하는 경우 Equals와 HashCode를 사용하는데 문제를 일으킬 수 있다.
HashMap의 getNode 메서드로 실제 key를 이용해 값을 가져오는 메서드이다. 이를 살펴보면 hash가 같은지 판단하고 key 입력이 null인지 그리고 equals를 이용해 동등성을 확인한다.
(자바의 HashMap은 내부 해시 충돌시 2차원 Node 테이블과 Sperate Chaining 방식으로 해결하고 있다.)
@Override
public int hashCode() {
int result = Short.hashCode(areaCode);
result = 31 * result + Short.hashCode(prefix);
result = 31 * result + Short.hashCode(lineNum);
return result;
}
소수로 31을 사용했는데 31은 최적화와 관련이있다. 31 * i는 (1 << 5) - i 와 같이 시프트 연산으로 컴파일러가 알아서 최적화해준다.
Short.hashCode는 단순하게 short value를 hashCode로 사용. 다만 Short 형은 크기가 작으므로 int로 형변환해준다.
Obejcts의 HashCode는 hashCode를 간결하게 구현할 수 있다. intellij 자동 완성에서는 이 메서드를 사용한다.
@Override
public int hashCode() {
return Objects.hash(lineNum, prefix, areaCode);
}
코드 자체는 간결하지만 책에 의하면 hashCode를 호출하는 비용이 꽤 크다고 한다. 매번 해쉬함수를 호출하고 싶지 않다면 캐싱하는 방법을 사용한다.
캐싱하는 방법은 몇가지 있지만 생성시 초기화하는 방법, 또는 lazy하게 초기화하는 방법이 있다. lazy 방식은 Thread-safe 하지 않으므로 이 부분을 고려해주어야 한다.
캐싱코드의 단점은 hashCode 변수가 인스턴스에 추가되고 이 부분을 구현해야 되서 꼭 필요한 객체의 인스턴스 변수를 남기고 싶은 때 좀 신경 쓰인다.
https://d2.naver.com/helloworld/831311 (hashMap)