[아이템 11] equals를 재정의하려거든 hashCode도 재정의하라
-
equals를 재정의한 클래스 모두에서 hashCode도 재정의해야함
-
그렇지 않으면 해당 클래스의 인스턴스를 HashMap이나 HashSet 같은 컬렉션의 원소로 사용할 때 문제를 일으킴
-
hashCode 재정의를 잘못했을 때 크게 문제되는 사항은 논리적으로 같은 객체는 같은 해시코드를 반환해야 하는 부분임
-
equals에서는 물리적으로 다른 두 객체를 논리적으로 같다고 했지만 hashCode에서는 이 둘을 전혀 다르다고 판단하여 서로 다른 값을 반환함
-
hashCode를 재정의하지 않으면 논리적 동치인 두 객체가 서로 다른 해시코드를 반환하여 규약이 깨짐
-
그리고 설령 같은 버킷에 담았어도 해시코드가 다른 엔트리끼리는 동치성 비교를 시도조차 하지 않도록 최적화되어 있어서 안 함
-
아래와 같이 구현한다면 최악의 상황임
@Override public int hashCode() { return 42; }
-
이는 모든 객체에게 똑같은 값만 내주어 모든 객체가 마치 연결리스트처럼 되버림, 객체가 많아지면 쓸 수 없게됨
-
좋은 해시 함수라면 서로 다른 인스턴스에 다른 해시코드를 반환함
-
hashCode를 재정의한다면 아래와 같은 방식으로 씀
-
int
변수result
를 선언한 후 값c
로 초기화함, 이때c
는 해당 객체의 첫번째 핵심 필드를 단계 2.a 방식으로 계산한 해시코드임(여기서 핵심 필드는equals
비교에 사용되는 필드를 말함) -
해당 객체의 나머지 핵심 필드
f
각각에 대해 다음 작업을 수행함a. 해당 필드의 해시코드
c
를 계산함i. 기본 타입 필드라면, Type.hashCode(f)를 수행함(여기서 Type은 해당 기본 타입의 박싱 클래스임) ii. 참조 타입 필드면서 이 클래스의 equals 메서드가 이 필드의 equals를 재귀적으로 호출해 비교한다면, 이 필드의 hashCode를 재귀적으로 호출함, 계산이 더 복잡해질 것 같으면, 이 필드의 표준형을 만들어 그 표준형의 hashCode를 호출함, 필드의 값이 null이면 0을 사용함 iii. 필드가 배열이라면, 핵심 원소 각각을 별도 필드처럼 다룸, 이상의 규칙을 재귀적으로 적용해 각 핵심 원소의 해시코드를 계산한 다음, 단계 2.b 방식으로 갱신함, 배열에 핵심 원소가 하나도 없다면 단순히 상수(0을 추천)를 사용함 모든 원소가 핵심 원소라면 Arrays.hashCode를 사용함
b. 단계 2.a에서 계산한 해시코드
c
로result
를 갱신함, 코드로는 다음과 같음
result = 31 * result + c;
-
result
를 반환함
-
hashCode를 다 구현했다면 이 메서드가 동치인 인스턴스에 대해 똑같은 해시코드를 반환할지 자문해봄
-
여기서 다른 필드로부터 계산해 낼 수 있는 필드는 모두 무시해도 됨,
equals
비교에 사용되지 않은 필드는 반드시 제외해야함 -
여기서 위와 같이 hashCode를 작성할 수 있고
Object
클래스에서 임의의 개수만큼 객체를 받아 해시코드를 계산해주는 정적 메서드인hash
를 사용할 수 있음(단, 성능이 민감하지 않은 상황에서만 쓰는게 좋음) -
클래스가 불변이고 해시코드를 계산하는 비용이 크다면 매번 새로 계산하기보다는 캐싱하는 방식을 고려해야 하는데 이때 지연 초기화 전략을 통해서 응용할 수 있음(주로 해시의 키로 사용될 것 같다면, 스레드 안전성을 고려해야함)
-
성능을 높인답시고 해시코드를 계산할 때 핵심필드를 생략하면 안됨
-
hashCode가 반환하는 값의 생성 규칙을 API 사용자에게 자세히 공표하지 말자, 그래야 클라이언트가 이 값에 의지하지 않고 추후에 계산 방식을 바꿀 수 있음
Author And Source
이 문제에 관하여([아이템 11] equals를 재정의하려거든 hashCode도 재정의하라), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gang_shik/아이템-11-equals를-재정의하려거든-hashCode도-재정의하라저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)