포스트

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에서 객체 비교를 제대로 이해하는 것은 문법보다, 도메인에서 무엇을 같은 것으로 볼 것인가를 명확히 정의하는 일에 가깝다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

댓글

아직 댓글이 없습니다