3장 이펙티브 자바 아이템 11

한주영·2023년 10월 12일
0

이펙티브자바

목록 보기
10/33

equals를 재정의하려거든 hashCode도 재정의하라

1.hashCode재정의를 잘못했을때 문제되는부분
-->논리적으로 같은 객체는 같은 해시코드를 반환해야한다

Map<PhoneNumber,String> m= new HashMap<>();
m.put(new PhoneNumber(707,867,5309),"제니");

이코드 다음에 get메서드를 실행하면 null을 반환
PhoneNumber클래스는 hashCode를 재정의하지않았기때문에 서로 다른 해시코드를 반환

2.사용해서는 안되는 예

@Override
public int hashCode() { return 42;}

1)모든객체에게똑같은 값만 내어준다
2)해시테이블의버킷하나의 담겨 마치 연결리스트처럼동작
3)평균수행시긴간이 O(1)이 아닌 O(n)으로 느려져서 객체가 많아지게되면 쓸수없게 됨

3.좋은 해시코드를 쓰는 요령

1)int변수 result선언후 값c로 초기화
c는 해당객체의 첫번째 핵심 필드를 단계2.a방식으로 계산한 해시코드

2)해당 객체의 나머지 핵심필드 f 각각에 대해 다음 작업을 수행

(1)기본타입 필드라면 Type.hasCode(f)를 수행

(2) 참조타입 필드면서 equals메서드가 해당 필드의 equals를 재귀적으로 호출해 비교한다면, 이 필드의 hashCode를 재귀적으로 호출

(3)필드가 배열이라면 핵심 원소를 각각 별도 필드처럼 다룬다
모든 원소가 핵심 원소라면 Arrays.hashCode를 사용

3)단계 2.a에서 계산한 해시코드 c로 result를 갱신한다

result=31*result+c;

-->31을 곱하는 이유: 31은 홀수이며 소수이기때문
-->곱할 숫자가 짝수이고 오버플로우 발생시 2를 곱하면 시프트 연산과 같은 결과를 주기때문에 정보를 잃게됨
-->소수를 곱하는것은 전통적으로 해온 방식

4)result를 반환한다.

  1. 클래스가 불변이고 해시코드를 계산하는 비용이크다면 매번 새로계산하기보다는 캐싱방식을 고려

-->객체가 주로 해시키로 사용될거같다면 인스턴스가 만들어질때 해시코드를 계산

5.성능을높이기위해 해시코드를 계산할때 핵심필드 생략은 안된다

  1. hashCode가 반환하는 값의 생성 규칙을 API사용자에게 자세히 공표X
    -->클라이언트에서 값에의지하지 않고 추후에 계산방식을 바꿀수있다

핵심정리
1)equals를 재정의할때는 hashCode도 반드시 재정의
2)재정의한 hashCode는 Object API 규약을 따라야한다
3) 서로다른 인스턴스라면 되도록 해시코드도 서로 다르게 구현해야한다

profile
백엔드개발자가 되고싶은 코린이:)

0개의 댓글