CS/Java

자바 equals / hashCode 오버라이딩 - collections 동작 원리를 기반으로

grove1212 2025. 8. 22. 17:21

Java에서 객체 비교, 진짜 똑같은지 어떻게 알까?

 

equals()와 hashCode()는 서로 연관이 있을까?
겉보기엔 같아 보여도, 사실 내부 동작은 전혀 다릅니다.


Object 클래스 기본 구현

public boolean equals(Object obj) {
    return this == obj; // 주소값 비교
}

public native int hashCode(); // 보통 객체 주소 기반
  • 오버라이딩하지 않은 상태에서는:
    1. equals() → this == obj → 주소값 동일 여부
    2. hashCode() → 객체 주소 기반 값 반환
  • 중요 포인트: equals()는 hashCode를 직접 사용하지 않습니다.
    기본 구현에서 주소값 비교와 hashCode 반환 방식이 같은 이유는 Java 내부 구현상의 우연일 뿐입니다.
    즉, Object.equals()는 주소값 직접 비교로 판단합니다.
  • 오버라이딩 후에는 hashCode()와 equals()가 완전히 독립적으로 정의될 수 있습니다.

Hash Code

객체를 식별하는 정수값을 의미한다.(고유하지 않음)

  • 해시 기반 컬렉션(HashMap, HashSet)에서 빠르게 검색하기 위해 사용됩니다.
  • 동작 방식:
  1. hashCode()를 통해 버킷 위치를 결정한다.
  2. 같은 버킷에 여러 객체가 존재하면 equals()로 실제 동일 여부를 비교한다.
  3. 두 객체가 동일하지 않다면 반드시 다른 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인 것은 아니다.