Java에서 객체 비교를 어떻게 해야 하는가
Java에서 객체 비교를 처음 배울 때 가장 먼저 헷갈리는 것은 ==와 equals()의 차이다. 여기에 hashCode()까지 얽히면 왜 같은 객체처럼 보이는데 비교 결과가 다르게 나오는지 혼란스러워지기 쉽다.
핵심은 무엇을 같다고 볼 것인지를 구분하는 데 있다.
==는 무엇을 비교하나
참조 타입에서 ==는 두 변수가 같은 객체를 가리키는지를 본다.
1
2
3
4
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false
두 객체의 내용은 같아도, 서로 다른 인스턴스라면 ==는 false다.
즉 ==는 값의 동일성이 아니라 참조의 동일성을 비교한다.
equals()는 무엇을 비교하나
equals()는 논리적인 동등성을 비교하기 위해 사용한다.
예를 들어 두 사용자 객체가 같은 회원 번호를 가지면 같은 사용자라고 볼지, 아니면 필드 전체가 같아야 같은 객체라고 볼지는 도메인에 따라 다르다.
이 기준을 코드로 정의하는 메서드가 equals()다.
Object.equals() 기본 구현의 한계
아무 것도 오버라이드하지 않으면 Object.equals()는 사실상 ==와 비슷하게 동작한다. 그래서 값 기준 비교를 원한다면 직접 오버라이드해야 한다.
왜 hashCode()도 함께 봐야 하나
HashMap, HashSet 같은 해시 기반 컬렉션은 equals()만 보지 않는다. 먼저 hashCode()로 버킷을 찾고, 그 다음 equals()로 최종 비교한다.
그래서 equals()만 오버라이드하고 hashCode()를 맞추지 않으면:
- 같은 값인데도 Set에서 중복 제거가 안 되거나
- Map 키 조회가 실패하거나
- 컬렉션 동작이 일관되지 않게 된다
즉, 논리적으로 같다고 판단한 객체는 같은 hashCode()를 가져야 한다.
어떤 필드를 기준으로 비교할 것인가
가장 중요한 판단은 “동등성의 기준”이다.
예를 들어:
- 회원 번호가 같으면 같은 사용자
- 주문 번호가 같으면 같은 주문
- 값 객체는 모든 핵심 필드가 같으면 같은 값
이 기준이 흐리면 equals() 구현도 흔들린다.
실무에서 주의할 점
변경 가능한 필드를 기준으로 비교하지 말 것
해시 기반 컬렉션에 들어간 뒤 값이 바뀌면, 같은 객체인데도 조회가 안 되는 문제가 생길 수 있다. 그래서 동등성 기준은 가능한 한 불변에 가까운 식별자나 핵심 값으로 잡는 편이 안전하다.
엔티티와 값 객체를 구분할 것
엔티티는 보통 식별자 중심으로 동등성을 판단하고, 값 객체는 내용 자체로 판단하는 경우가 많다. 두 유형을 같은 방식으로 다루면 오히려 혼란이 커진다.
정리
==는 같은 참조인지 비교한다equals()는 논리적으로 같은지 비교한다hashCode()는 해시 컬렉션에서의 일관성을 보장한다
Java에서 객체 비교를 제대로 이해하는 것은 문법보다, 도메인에서 무엇을 같은 것으로 볼 것인가를 명확히 정의하는 일에 가깝다.
댓글
아직 댓글이 없습니다