Java 개발을 하다 보면 equals()와 hashCode() 메서드를 오버라이딩해야 하는 상황이 자주 발생합니다. 두 메서드를 올바르게 오버라이딩하지 않으면 예기치 않은 동작이 발생할 수 있습니다. 이번 글에서는 두 메서드를 함께 오버라이딩해야 하는 이유를 구체적인 예제와 함께 설명합니다. ✍️
equals()와 hashCode()란 무엇인가? 🤔
- equals() 메서드: 두 객체가 논리적으로 동등한지 비교합니다. 기본적으로 Object 클래스에서 제공하는 equals()는 두 객체의 참조값(메모리 주소)을 비교합니다.
- hashCode() 메서드: 객체를 식별하는 정수 값을 반환합니다. 이 값은 해시 기반 컬렉션(예: HashMap, HashSet)에서 객체를 저장하고 검색하는 데 사용됩니다.
두 메서드의 관계 🔗
equals()와 hashCode()는 다음과 같은 규칙에 따라 동작해야 합니다:
- equals()가 true를 반환하는 두 객체는 동일한 hashCode() 값을 가져야 합니다.
- hashCode() 값이 같은 객체가 반드시 equals()에서 true를 반환할 필요는 없습니다.
이 규칙을 지키지 않으면 HashMap이나 HashSet과 같은 컬렉션에서 객체를 올바르게 처리하지 못합니다.
왜 두 메서드를 함께 오버라이딩해야 할까? ⚠️
1. hashCode()를 오버라이딩하지 않은 경우의 문제
import java.util.HashSet;
class Person {
private String name;
public 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) {
Person p1 = new Person("Alice");
Person p2 = new Person("Alice");
HashSet<Person> set = new HashSet<>();
set.add(p1);
System.out.println(set.contains(p2)); // false
}
}
문제 설명 📉
- equals() 메서드를 오버라이딩했으므로 p1과 p2는 논리적으로 동등합니다.
- 그러나 hashCode()를 오버라이딩하지 않았기 때문에 HashSet은 p2를 p1과 동일한 객체로 인식하지 못합니다.
2. equals()를 오버라이딩하지 않은 경우의 문제
import java.util.HashSet;
class Person {
private String name;
public Person(String name) {
this.name = name;
}
@Override
public int hashCode() {
return name.hashCode();
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("Alice");
Person p2 = new Person("Alice");
HashSet<Person> set = new HashSet<>();
set.add(p1);
System.out.println(set.contains(p2)); // false
}
}
문제 설명 📉
- hashCode()는 오버라이딩했으나 equals()를 오버라이딩하지 않았기 때문에 HashSet은 두 객체가 다르다고 판단합니다.
올바른 오버라이딩 예제 ✅
import java.util.HashSet;
class Person {
private String name;
public 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.hashCode();
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("Alice");
Person p2 = new Person("Alice");
HashSet<Person> set = new HashSet<>();
set.add(p1);
System.out.println(set.contains(p2)); // true
}
}
결과 설명 🌟
- equals()와 hashCode()를 모두 오버라이딩했기 때문에 HashSet은 p1과 p2를 동일한 객체로 인식합니다.
결론 🎯
- equals()와 hashCode()는 항상 함께 오버라이딩해야 합니다.
- equals()는 객체의 논리적 동등성을 정의하고, hashCode()는 해시 기반 컬렉션의 효율적인 동작을 보장합니다.
- 두 메서드를 올바르게 오버라이딩하면 예기치 않은 동작을 방지하고, 코드의 신뢰성을 높일 수 있습니다.
'IT 개발 라이프 > Back_End' 카테고리의 다른 글
추상 클래스와 인터페이스 (0) | 2024.12.11 |
---|---|
객체지향 설계의 5원칙 (SOLID) (0) | 2024.12.11 |
ORM(Object-Relational Mapping) 이란? 🔍 (1) | 2024.12.06 |
🍪 쿠키(Cookie)와 세션(Session) 이란? (3) | 2024.12.06 |
스프링 핵심 개념: IoC, DI, AOP 알아보기 🌟 (1) | 2024.12.05 |