Java에서 객체 비교, 진짜 똑같은지 어떻게 알까?
equals()와 hashCode()는 서로 연관이 있을까?
겉보기엔 같아 보여도, 사실 내부 동작은 전혀 다릅니다.
Object 클래스 기본 구현
public boolean equals(Object obj) {
return this == obj; // 주소값 비교
}
public native int hashCode(); // 보통 객체 주소 기반
- 오버라이딩하지 않은 상태에서는:
- equals() → this == obj → 주소값 동일 여부
- hashCode() → 객체 주소 기반 값 반환
- 중요 포인트: equals()는 hashCode를 직접 사용하지 않습니다.
기본 구현에서 주소값 비교와 hashCode 반환 방식이 같은 이유는 Java 내부 구현상의 우연일 뿐입니다.
즉, Object.equals()는 주소값 직접 비교로 판단합니다. - 오버라이딩 후에는 hashCode()와 equals()가 완전히 독립적으로 정의될 수 있습니다.
Hash Code
객체를 식별하는 정수값을 의미한다.(고유하지 않음)
- 해시 기반 컬렉션(HashMap, HashSet)에서 빠르게 검색하기 위해 사용됩니다.
- 동작 방식:
- hashCode()를 통해 버킷 위치를 결정한다.
- 같은 버킷에 여러 객체가 존재하면 equals()로 실제 동일 여부를 비교한다.
- 두 객체가 동일하지 않다면 반드시 다른 hashCode를 가질 필요는 없지만, 가능한 다른 값을 가지는 것이 좋다.
Equals
동일한 내용을 가지고 있는 객체인지 판단한다.
- 오버라이딩 전 : 주소값 기반 비교(==)
- 오버아리딩 후 : 내용물 기반 비교
hashCode & equals 재정의 예시
class Person {
String name;
Person(String name) { this.name = name; }
@Override
public boolean equals(Object obj) {
return obj instanceof Person && this.name.equals(((Person)obj).name);
}
@Override
public int hashCode() {
return Object.hash(name);
}
}
HashMap, HashSet 동작 원리
- hashCode() → 버킷 위치 결정
- 같은 hashCode 값을 가진 객체들 → 같은 버킷에 모임
- 버킷 안에서 equals() → 실제 객체 동일 여부 확인
단계역할
hashCode() | 빠른 검색을 위해 버킷 위치 결정 |
---|---|
equals() | 충돌 시 실제 객체 동일 여부 확인 |
컬렉션 내부 | hashCode 같은 객체가 같은 버킷에 모이고, equals로 최종 판단 |
핵심: equals() 자체가 hashCode를 기반으로 비교하지 않는다.
equals()는 객체 내부 필드 값을 기반으로 논리적 동등성을 판단한다.
Java 규칙
- a.equals(b)가 true이면, 반드시 **a.hashCode() == b.hashCode()**이어야 한다.
- 반대로, hashCode가 같다고 equals가 true인 것은 아니다.