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

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

🔑 핵심 내용

✔ equals를 재정의한 클래스는 반드시 hashCode도 재정의해야 한다 그렇지 않으면 HashMap, HashSet 같은 컬렉션에서 문제가 생긴다 ✔ 좋은 Hashcode 만들기


hashCode란 무엇일까?

  • hashCode는 객체를 구분하는 정수값(숫자)이다

  • 이 숫자는 해시 기반 자료구조에서 객체를 빨리 찾는 데 사용한다

hashCode 규약

  1. 실행 중에는 같은 객체의 hashCode() 값이 변하면 안 된다

  2. equals로 같다고 판단된 두 객체는 같은 hashCode 값을 가져야 한다

  3. equals로 다르다고 판단된 두 객체의 hashCode는 다를 수도, 같을 수도 있다

🚫 나쁜 예시 : equals만 재정의하고 hashCode는 재정의하지 않은 경우

✅ 좋은 예시 : equals와 hashCode 둘다 재정의 한 경우

Image

좋은 hashCode 만드는 법

  1. int 변수 result를 선언하고 첫 번째 필드의 해시코드로 초기화

  2. 나머지 필드의 해시코드를 계산해서 result 값에 더함

  3. result 값을 리턴

hashCode() 작성 예시

hashCode() 작성 시 고려해야 할 사항

  • 숫자 타입 (int, long 등) → 그냥 사용

  • 문자열 (String) → .hashCode() 호출

  • 객체 → 해당 객체의 hashCode() 사용

  • 배열 → Arrays.hashCode() 사용

  • null 값 → 0 사용

왜 31을 곱할까?

  1. 31은 소수(Prime Number)라서 해시 충돌을 줄일 수 있다

  2. 31은 홀수라서 오버플로우 발생 시 정보 손실을 막을 수 있다

  3. 31 * x는 (x << 5) - x로 바꿀 수 있어 연산 속도가 빠르다

    x << 5 는 x _ 32 와 같음 (왼쪽으로 5비트 이동 = 2^5 = 32 곱하기) 즉, 31 _ x 를 32 * x - x 로 변경하면 빠른 연산이 가능!

더 쉬운 방법: Objects.hash 사용하기

  • Objects.hash 를 사용하면 편리하지만, 성능이 저하 된다는 단점이 있다

  • 성능이 중요한 애플리케이션이 아닌 일반적인 애플리케이션에서는 이 성능 차이가 크게 문제되지 않을 수 있다


🧩 어려웠던 점

  • hashCode()를 왜 재정의해야 하는지 처음에는 이해하기 어려웠음.

  • equals()와 hashCode()의 관계를 정확히 정리하는 것이 헷갈렸다

  • 자바가 자동으로 해결해주지 않아서 개발자가 직접 관리해야 하는 부분이라 처음에는 어려웠다

💭 느낀 점

  • hashCode()를 재정의하지 않으면, 같은 객체라도 컬렉션에서 찾지 못할 수 있다는 것에 놀랐다

  • 31을 곱하는 이유가 단순한 최적화가 아니라, 실제 성능에 영향을 미친다는 점이 흥미로웠다

Last updated