equals를 재정의한 클래스 모두에서 hashcode도 재정의해야 한다. 그렇지 않으면 hashCode 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 컬렉션의 원소로 사용할 때 문제를 일으킨다.
The general contranct of hashCode
import java.util.HashMap;
class AmbiguousInteger {
private final int value;
AmbiguousInteger(int value) {
this.value = value;
}
}
class Main {
public static void main(String[] args) {
HashMap<AmbiguousInteger, Integer> map = new HashMap<>();
map.put(new AmbiguousInteger(1), 1); // a
System.out.println(map.get(new AmbiguousInteger(1))); // b
}
}
b의 결과값은 예상과 다르게 null이다. 그 이유는 hashcode를 재정의 해주지 않으면 Object의 hashcode 함수를 사용할테니 물리적으로 다른 두 객체가 논리적으로 같은지 알 수 없다.
a라인과 b라인을 실행 시켰을 때, 그림을 그려봤다. 왜 null을 반환하는지 이해할 수 있을 것이다.
public int hashCode() { return 9; }
위와 같이 hashCode를 재정의하면 해결이 되긴 된다. 위에서 본 규약의 3가지 조건에도 모두 만족한다. 그런데 문제가 있다.
hashMap에 추가되는 모든 노드의 해시값이 같기 때문에, 버킷의 동일한 index에 linkedList와 같은 형태로 저장되기 때문에 성능이 떨어지게 된다. (선형시간)
@Override
public int hashCode() {
int c = 31;
int result = Short.hashCode(areaCode);
result = c * result + Short.hashCode(prefix);
result = c * result + Short.hashCode(lineNumber);
return result;
}
@Override public int hashCode() {
return Objects.hash(lineNum, prefix, areaCode);
}
하지만 내부적으로 auto boxing이 일어나서 성능이 떨어진다.