Java에서 equals() 및 hashCode() 메서드는 HashMap, HashSet 및 기타와 같은 컬렉션의 올바른 작동에 매우 중요합니다. 이 질문은 종종 초보 개발자들이 간과하지만, 이러한 메서드의 계약을 위반하면 애플리케이션 로직에서 발견하기 어려운 오류가 발생할 수 있습니다.
질문 배경:
Java에서 모든 클래스는 기본적으로 Object 클래스로부터 equals() 및 hashCode() 메서드를 상속받습니다. 기본적으로 equals()는 객체의 참조(즉, 메모리 내 물리적 위치)를 비교하고, hashCode()는 각 객체에 대해 고유한 코드를 반환합니다. 그러나 사용자 정의 클래스에서는 객체의 내용을 비교해야 할 때가 많습니다.
문제:
equals() 및 hashCode() 메서드가 재정의되지 않거나 잘못 재정의되면 해시 기반의 컬렉션에서 객체가 예상치 않게 작동할 수 있습니다. 이로 인해 요소가 누락되거나 중복되거나 검색 오류가 발생할 수 있습니다.
해결책:
항상 두 메서드를 함께 재정의하고 계약을 엄격하게 준수해야 합니다:
a.equals(b) == true이면 a.hashCode() == b.hashCode()이어야 합니다.a.equals(b) == false인 경우 hashCode에 대한 요구 사항은 고유성이 필수는 아닙니다.올바른 구현 예:
public class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } }
주요 특징:
equals() 메서드는 반사적, 대칭적, 추이적, 일관성이어야 합니다.hashCode() 메서드는 변경 불가능한 데이터에 대해 객체에 대해 동일한 값을 반환해야 합니다.HashSet에 저장될 클래스에서 hashCode() 없이 equals()만 사용할 수 있습니까?
아니요. equals()만 재정의하면 해시 기반 컬렉션이 객체의 고유성을 올바르게 판단하지 못합니다. HashSet은 먼저 hashCode를 비교하고, 그 다음에 equals를 비교합니다.
equals()와 hashCode()에서 클래스의 모든 필드를 사용하는 것이 필수입니까?
아니요. 클래스의 논리적 정체성에 의미 있는 필드만 사용하면 됩니다. 예를 들어, 객체에 내부적으로 고유한 식별자가 있다면 그것만으로 충분합니다.
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return Objects.equals(id, user.id); }
equals()에서 직접 필드 대신 getter에 기반할 수 있습니까?
보통은 가능하지만 부작용이 없고 getter가 안정적일 경우에만 그렇습니다. 그러나 getter가 여러 호출에서 다른 값을 반환할 위험이 있으므로, 그 경우 동작이 예측 불가능해질 수 있습니다.
equals()를 재정의했을 때 hashCode()를 재정의하지 않음.hashCode() 계산에 가변 필드를 사용함.한 개발자가 User 클래스를 구현하고 hashCode()를 잊고 equals()만 정의합니다. 결과적으로 HashSet에 객체를 추가하고 검색할 때 중복이 발생하고 요소가 "사라지는" 문제가 생깁니다.
장점:
단점:
한 개발자가 두 메서드를 계약에 따라 정확하게 구현하고, 동등성과 해시 로직 내에서 id만 사용합니다. 컬렉션은 예상대로 작동하고, 검색 및 저장이 올바르게 이루어집니다.
장점:
단점: