11. equals를 재정의하려거든 hashCode도 재정의하라
11. equals를 재정의하려거든 hashCode도 재정의하라
🔑 핵심 내용
✔ equals를 재정의한 클래스는 반드시 hashCode도 재정의해야 한다 그렇지 않으면 HashMap, HashSet 같은 컬렉션에서 문제가 생긴다 ✔ 좋은 Hashcode 만들기
hashCode란 무엇일까?
hashCode는 객체를 구분하는 정수값(숫자)이다
이 숫자는 해시 기반 자료구조에서 객체를 빨리 찾는 데 사용한다
hashCode 규약
실행 중에는 같은 객체의 hashCode() 값이 변하면 안 된다
equals로 같다고 판단된 두 객체는 같은 hashCode 값을 가져야 한다
equals로 다르다고 판단된 두 객체의 hashCode는 다를 수도, 같을 수도 있다
🚫 나쁜 예시 : equals만 재정의하고 hashCode는 재정의하지 않은 경우
✅ 좋은 예시 : equals와 hashCode 둘다 재정의 한 경우
좋은 hashCode 만드는 법
int 변수 result를 선언하고 첫 번째 필드의 해시코드로 초기화
나머지 필드의 해시코드를 계산해서 result 값에 더함
result 값을 리턴
hashCode() 작성 예시
hashCode() 작성 시 고려해야 할 사항
숫자 타입 (int, long 등) → 그냥 사용
문자열 (String) → .hashCode() 호출
객체 → 해당 객체의 hashCode() 사용
배열 → Arrays.hashCode() 사용
null 값 → 0 사용
왜 31을 곱할까?
31은 소수(Prime Number)라서 해시 충돌을 줄일 수 있다
31은 홀수라서 오버플로우 발생 시 정보 손실을 막을 수 있다
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