Java equals()와 hashCode() 완벽 이해하기
Java를 공부하다 보면 정말 많이 등장하는 메서드가 바로:
equals()
hashCode()
입니다.
특히:
- HashMap
- HashSet
- 중복 제거
- 객체 비교
- JPA Entity
- Lombok
까지 실무 전체와 깊게 연결됩니다.
초보 시절에는 보통:
equals = 값 비교
hashCode = 해시값
정도로 외우고 넘어가기 쉽습니다.
하지만 실제로는:
- Object 계약(contract)
- Hash 충돌 처리
- Collection 내부 구조
- immutable 설계
- 성능 문제
까지 전부 연결됩니다.
심지어 실무에서는:
equals/hashCode 잘못 구현
↓
HashMap 조회 실패
↓
장애 발생
도 실제로 많이 일어납니다.
이번 글에서는:
- equals() 의미
- hashCode() 의미
- 왜 둘 다 필요한가
- HashMap 내부 동작
- Object contract
- Lombok 주의점
- 실무 장애 사례
까지 깊게 정리해보겠습니다.
1. 모든 객체는 Object를 상속한다
Java의 모든 클래스는 결국:
java.lang.Object
상속.
즉 기본적으로:
equals()
hashCode()
보유.
2. 기본 equals() 동작
Object의 기본 equals는 사실상:
==
와 거의 동일.
즉:
주소(reference) 비교
입니다.
3. 예시
User u1 = new User("Kim");
User u2 = new User("Kim");
System.out.println(u1.equals(u2));
결과:
false
4. 왜 false일까?
현재:
서로 다른 객체
이기 때문.
즉:
Heap 주소 다름
5. 하지만 우리가 원하는 건?
보통은:
내용 비교
원함.
즉:
이름이 같으면 같은 사용자
처럼 판단하고 싶음.
6. 그래서 equals 재정의
예:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User))
return false;
User user = (User) o;
return Objects.equals(name, user.name);
}
7. 이제 결과
u1.equals(u2)
↓
true
가능.
8. hashCode란?
Hash function 기반 개념.
hashCode는:
객체를 정수(int) 값으로 변환한 결과
입니다.
9. 왜 필요할까?
핵심 목적:
빠른 검색
입니다.
특히:
- HashMap
- HashSet
에서 핵심.
10. HashMap 내부 동작 다시 보기
map.put(user, value);
실제로:
user.hashCode()
↓
bucket 위치 계산
수행.
11. equals만 구현하면 안 되는 이유
매우 중요합니다.
예:
equals만 재정의
hashCode 미재정의
문제 발생 가능.
12. 실제 문제 예시
Set<User> set = new HashSet<>();
set.add(new User("Kim"));
System.out.println(
set.contains(new User("Kim"))
);
13. 기대 결과
true
처럼 보임.
14. 그런데 실제론 false 가능
왜냐하면:
hashCode 다름
일 수 있기 때문.
15. HashSet 동작 순서
HashSet은 먼저:
hashCode()
확인.
그리고 같은 bucket 내부에서:
equals()
비교.
16. 즉 둘 다 필요
핵심:
hashCode 먼저
equals 나중
객체 전체의 해시값을 확인 후, 객체 내부 키까지 확인
17. Object Contract(계약)
Java는 중요한 규칙 정의.
18. 핵심 규칙
매우 중요.
equals가 true면
hashCode도 반드시 같아야 한다
hash(객체A) => 결과123
hash(객체A) => 필연적으로 결과123
19. 반대는 성립 안 함
즉:
hashCode 같다고
equals true일 필요는 없음
충돌 가능.
해시는 어떤 크기든 정해진 길이 값으로 치환되기 때문에 중복이 있을 수 있음
20. 예시
A.hashCode() == B.hashCode()
여도:
A.equals(B)
는 false 가능.
21. 왜 이런 규칙 필요할까?
HashMap 구조 때문.
같은 객체인데
다른 bucket 저장되면
검색 불가능
문제 발생.
22. 올바른 구현 예시
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User))
return false;
User user = (User) o;
return Objects.equals(id, user.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
23. 왜 보통 id 기준 비교할까?
실무에서는:
식별자(identity)
중심 비교 많음.
예:
- 회원 ID
- 주문번호
- UUID
등.
24. mutable 필드 위험
매우 중요합니다.
예:
name 변경 가능
인데 hashCode 기반이면?
25. 위험한 상황
map.put(user, value);
user.setName("Lee");
현재:
hashCode 변경 가능
즉:
Map에서 못 찾는 상황
발생 가능.
26. 그래서 immutable key 중요(immutable 설계)
HashMap key는 보통:
변하지 않는 값 사용
추천.
대표:
- String
- UUID
- Integer
27. String이 안전한 이유
String 은:
immutable
입니다.
즉 hashCode 안정적.
28. hashCode 품질도 중요
안 좋은 예:
@Override
public int hashCode() {
return 1;
}
29. 문제
모든 객체 충돌
즉:
HashMap 성능 O(N)
까지 저하 가능. 성능 문제
30. 좋은 hashCode 특징
핵심:
고르게 분산
되는 것.
31. Java Objects.hash()
대표 구현:
Objects.hash(id, name)
간편하게 hashCode 생성 가능.
32. Lombok @EqualsAndHashCode
Project Lombok 에서 제공.
예:
@EqualsAndHashCode
33. 장점
자동 생성 가능.
코드 간단.
34. 하지만 실무 주의점
매우 중요.
Entity에 무분별하게 사용 위험 가능.
35. JPA Entity 문제
Jakarta Persistence 환경에서:
Lazy Loading
Proxy
와 충돌 가능.
36. 대표 문제
equals 호출 시:
불필요한 DB 조회
가능.
37. Entity equals 실무 전략
보통:
PK 기반 비교
사용.
하지만 생성 전 ID null 문제도 존재.
매우 조심 필요.
38. Set에서 equals/hashCode 중요
HashSet은:
중복 제거 기준
으로 equals/hashCode 사용.
39. Collection 전체와 연결
대표 사용처:
| 컬렉션 | 사용 |
| HashMap | key 비교 |
| HashSet | 중복 제거 |
| ConcurrentHashMap | key 비교 |
40. == 와 equals 차이
매우 중요.
| 비교 | 의미 |
| == | 주소 비교 |
| equals | 논리 비교 |
41. String 비교 실수
안 좋은 예:
if (a == b)
보통은:
a.equals(b)
사용.
42. 실무에서 자주 하는 실수
1) equals만 구현
HashMap 동작 이상 가능.
2) mutable 필드 사용
Map 검색 실패 가능.
3) == 로 문자열 비교
매우 흔한 실수.
4) Lombok 무지성 사용
JPA Entity 문제 가능.
43. 핵심 흐름 요약
hashCode()
↓
bucket 위치 결정
↓
equals()
↓
진짜 동일 객체 판별
44. 가장 중요한 핵심 한 줄
equals는 “논리적 동일성”,
hashCode는 “빠른 검색 위치 계산”을 위한 것이다
입니다.
45. 정리
equals()와 hashCode()는 단순 메서드가 아닙니다.
실제로는:
- HashMap 내부 구조
- Hash 충돌 처리
- Collection 성능
- 객체 동일성
- JPA Entity 설계
전체와 연결되는 Java 핵심 개념입니다.
특히 실무에서는:
- Object Contract
- immutable key
- equals/hashCode 재정의
- Lombok 주의점
- HashMap 동작 원리
를 정확히 이해하는 것이 매우 중요합니다.
다음 글에서는:
Comparable vs Comparator
를 정렬 전략, TreeMap/TreeSet 내부 동작, 람다 기반 정렬까지 포함해서 깊게 정리해보겠습니다.
'language > java' 카테고리의 다른 글
| Java Iterator와 Iterable 완벽 이해하기 (0) | 2026.05.27 |
|---|---|
| Java Comparable vs Comparator 완벽 이해하기 (0) | 2026.05.27 |
| Java Hash 충돌(Hash Collision) 처리 방식 완벽 이해하기 (0) | 2026.05.27 |
| Java HashMap 내부 구조 완벽 이해하기 (0) | 2026.05.27 |
| Java ArrayList vs LinkedList 완벽 비교 (0) | 2026.05.27 |
댓글