equals() 메서드는 두 객체가 "같은지" 결정합니다. 기본적으로 참조를 비교하지만(즉, ==), 종종 클래스(예: 엔터티, 값 객체)는 데이터에 대한 논리적 비교를 요구합니다.
재정의해야 할 때:
요구 사항:
예:
public class Person { private String email; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return Objects.equals(email, person.email); } @Override public int hashCode() { return Objects.hash(email); } }
두 객체가 equals()에서 같다면, 그들의 hashCode()는 항상 같아야 하나요?
답변: 네! 이는 Java 계약의 요구 사항입니다. 그러나 반대는 사실이 아닙니다: 동일한 hashCode를 가진 두 객체는 equals()에서 같지 않을 수 있습니다 — 해시 코드가 서로 다른 객체에서 일치할 수 있습니다(충돌).
오류 예:
person1.equals(person2); // true person1.hashCode() != person2.hashCode(); // 오류!
이야기
기업 애플리케이션에서 사용자 엔터티가 HashSet에 포함되었습니다. equals가 재정의되었으나 hashCode는 되지 않았습니다. equals에 영향을 미치는 필드가 수정된 후, HashSet은 이 객체를 "잃었습니다": contains 메서드의 검색 시도는 같은 데이터에 대해서도 false를 반환했습니다.
이야기
IoT 프로젝트에서 엔터티는 일시적으로 id로만 비교되었고, 이후에는 이름을 고려하는 equals로 논리를 변경했습니다. HashMap은 예측할 수 없는 방식으로 작동하고, 키 업데이트 시 중복이 발생했습니다 — equals/hashCode 계약이 구현 버전의 혼동으로 인해 위반되었습니다.
이야기
주문 비교 API를 작성할 때 두 개의 서로 다른 클래스가 각자의 equals를 구현했으며, 하나는 getClass()를 호출하고 다른 하나는 instanceof를 사용했습니다. 이는 주문의 비대칭 비교 및 컬렉션 및 비즈니스 로직 사용 시 버그를 초래했습니다.