1. 개요
Java에서 equals
와 hashCode
메서드를 올바르게 재정의하는 것은 중요합니다. 특히, HashMap
, HashSet
등 해싱 기반 컬렉션에서 객체를 효율적으로 저장하고 검색하려면 필수적입니다. 이 문서에서는 왜 이 두 메서드를 재정의해야 하는지, 재정의하지 않으면 발생할 수 있는 문제와 함께 구체적인 예제와 함께 설명합니다.
2. equals
와 hashCode
의 역할
2.1 equals
메서드
- 객체 비교: 두 객체가 논리적으로 같은지 판단합니다.
- 기본 구현:
Object
클래스의 기본equals
는 참조 주소를 비교하므로, 동일 객체가 아니면 항상false
를 반환합니다.
2.2 hashCode
메서드
- 해싱 알고리즘: 객체의 해시 코드를 반환합니다. 이 해시 코드는 객체를
HashMap
,HashSet
등의 컬렉션에서 **버킷(bucket)**에 저장하거나 검색하는 데 사용됩니다. - 기본 구현:
Object
클래스의 기본hashCode
는 객체의 메모리 주소를 기반으로 해시 값을 생성합니다.
3. equals
와 hashCode
의 관계
3.1 두 메서드의 계약 (Contract)
- 계약 조건:
- 두 객체가
equals
로 같다고 판단되면,hashCode
는 반드시 동일해야 합니다. - 반대로, 두 객체의
hashCode
가 다르면,equals
는false
여야 합니다. hashCode
가 같다고 해서equals
가 항상true
를 반환하는 것은 아닙니다.
- 두 객체가
- 이 계약을 지키지 않으면 해싱 기반 컬렉션에서 예기치 않은 동작이 발생합니다.
4. 왜 equals
와 hashCode
를 재정의해야 하는가?
4.1 equals
만 재정의하고 hashCode
는 재정의하지 않을 경우
다음과 같은 문제가 발생할 수 있습니다:
- 두 객체가
equals
로 같아도 다른 해시코드를 반환합니다. - 이로 인해 동일 객체로 인식되지 않아,
HashSet
에서 중복 저장되거나HashMap
에서 값을 찾을 수 없습니다.
예제:
class Person {
String name;
Person(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return name.equals(person.name);
}
}
public class Main {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
Person p1 = new Person("John");
Person p2 = new Person("John");
set.add(p1);
System.out.println(set.contains(p2)); // false
}
}
4.2 hashCode
만 재정의하고 equals
를 재정의하지 않을 경우
- 두 객체가 같은 해시코드를 가지더라도
equals
가 다르다면, 컬렉션에서 올바르게 검색되지 않습니다.
5. 올바른 재정의 방법
5.1 equals
재정의
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return name.equals(person.name);
}
5.2 hashCode
재정의
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
6. equals
와 hashCode
를 모두 재정의한 예제
class Person {
String name;
Person(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return name.equals(person.name);
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
}
public class Main {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
Person p1 = new Person("John");
Person p2 = new Person("John");
set.add(p1);
System.out.println(set.contains(p2)); // true
}
}
7. 결론
equals
와 hashCode
메서드의 재정의는 Java에서 객체를 비교하거나 해싱 컬렉션을 사용할 때 필수적입니다. 두 메서드를 올바르게 재정의함으로써 논리적 동일성을 정확히 구현하고, 예기치 않은 동작을 방지할 수 있습니다.
이제 계약 조건을 기억하며 코드를 작성해 보세요!