Item 9. equals 메소드를 오버라이드 할 때는 hashcode 메소드도 항상 같이 오버라이드 하자.
개발 이야기/Effective Java 2010. 3. 11. 00:55equals 메소드를 오버라이드 하는 모든 클래스에서는 반드시 hashcode 메소드도 오버라이드 해야 한다. 그렇지 않으면 Obejct.hashcode 메소드의 보편적 계약을 위반하게 된다.
자바 API 문서의 계약 사항은 다음과 같다.
- 애플리케이션 실행 중에 같은 객체에 대해 한 번 이상 호출 되더라도 hashCode 메소드는 같은 정수를 일관성 있게 반환해야 한다.
- equals(Object) 메소드 호출 결과 두 객체가 동일하다면, 두 객체 각각에 대해 hashCode 메소드를 호출 했을 때 같은 정수 값이 나와야 한다.
- equals(Object) 메소드 호출 결과 두 객체가 다르다고 해서 두 객체 각각에 대해 hashCode 메소드를 호출 했을 때 반드시 다른 정수 값이 나올 필요는 없다. 그러나 같지 않은 객체들에 대해 hashCode 메소드에서 서로 다른 정수 값을 반환하면 이 메소드를 사용하는 해시 컬렉션들의 성능을 향상시킬 수 있음을 알아야 한다.
중요한 것은 hashCode의 오버라이딩에 실패했을 때 두번째 조항 즉 동일한 객체들은 같은 해시 코드 값을 가져야 한다는 것이 위배된다.
import java.util.*; public final class PhoneNumber { public PhoneNumber(int areaCode, int prefix, private static void rangeCheck(int arg, int max, @Override public boolean equals(Object o) { |
아래와 같이 클래스를 HashMap과 함께 사용한다고 해보자
public static void main(String[] args) { Map<PhoneNumber, String> m = new HashMap<PhoneNumber, String>(); m.put(new PhoneNumber(707, 867, 5309), "Jenny"); System.out.println(m.get(new PhoneNumber(707, 867, 5309))); } } |
이 시점에서 m.get(new PhoneNumber(707, 867, 5309), "Jenny");을 호출하면 "Jenny"가 반환될 것 같지만 실제로는 null이 반환된다. 여기서 두개의 PhoneNumber 인스턴스가 개입되어 있는데 하나는 HashMap에 삽입할 때 키로 사용되었고 첫번째와 동일한 값을 갖는 두번째 인스턴스는 검색 키에서 사용되었다. 즉 PhoneNumber 클래스에서 hashCode 메소드를 오버라이드 하지 않아서 두 인스턴스가 서로 다른 해시 코드 값을 갖게 된 것이다.
하지만 모든 객체가 다 똑같은 해시 코드를 갖게 되서는 안된다. 좋은 해시 메소드는 동일하지 않은 객체들에 대해 서로 다른 해시 코드를 만든다. 바로 이것이 hashCode 계약의 세번째 조항의 의미이다.
@Override public int hashCode() { int result = 17; result = 31 * result + areaCode; result = 31 * result + prefix; result = 31 * result + lineNumber; return result; } |
이 메소드에서는 PhoneNumber 인스턴스의 세가지 중요한 필드만으로도 간단히 연산한 결과를 반환하므로 동일한 PhoneNumber 인스턴스들은 똑같은 해시 코드 값을 갖는다. 이런 형태로 구현해야 한다.
'개발 이야기 > Effective Java' 카테고리의 다른 글
Item 24. 컴파일 경고 메시지가 없게 하자. (0) | 2010.03.22 |
---|---|
Item 10. toString 메소드는 항상 오버라이드 하자. (0) | 2010.03.11 |
Item 8. equals 메소드를 오버라이딩 할 때는 보편적 계약을 따르자. (0) | 2010.03.10 |
Item 7. 파이널라이저(Finalizer)의 사용을 피하자 (0) | 2010.03.08 |
Item 6. 쓸모 없는 객체 참조를 제거하자. (0) | 2010.03.08 |