equalshashCode 는 함께 재정의해야 한다!

→ 그렇지 않으면, 컬렉션의 원소를 사용할 때 문제 발생함

<aside> <img src="/icons/checkmark_orange.svg" alt="/icons/checkmark_orange.svg" width="40px" />

Object 명세 규약 중 일부

이 중, hashCode 재정의를 잘못했을 때 두 번째 조항이 가장 큰 문제가 된다.

물리적으로 다른 두 객체를 논리적으로 같은 객체다고 할 수 있고, 이는 같은 해시코드를 반환해야 한다. 하지만 잘못된 재정의는 hashCode() 호출 시, 전혀 다르다고 판단하고 서로 다른 값을 반환한다.

Map<Member, String> m = new HashMap<>();

m.put(new Member(1, 26), "승히");
m.get(new Member(1, 26));  // null!

// 서로 다른 두 객체의 해시코드가 다르기 때문

좋은 해시 함수

이상적인 해시 함수는 주어진 서로 다른 인스턴스들을 32비트 정수 범위에 균일하게 분배하는 것이다.

다음은 좋은 hashCode를 작성하는 간단한 요령이다:

  1. int 변수 result 선언한 후, 값 a 로 초기화한다.

  2. 해당 객체의 나머지 핵심 필드 f는 각각 다음 작업을 수행한다.

    1. 해시코드 a 를 계산
      1. 기본 타입 필드라면 → Type.hashCode(f) 수행
      2. 참조 타입 필드 & 해당 클래스의 equals()가 필드의 equals() 를 재귀 호출해 비교한다면 → 필드의 hashCode 재귀 호출
      3. 배열의 모든 원소가 핵심원소라면 → Arrays.hashCode 사용
    2. result 를 해시코드 a로 갱신
  3. result 반환