Next-Squad/Interview-Question

[Java] 47. equals()와 hashCode()를 함께 오버라이딩 해야하는 이유가 무엇일까요?

CMSSKKK opened this issue · 1 comments

equals()와 hashCode()를 함께 오버라이딩 해야하는 이유가 무엇일까요?

키워드

Hash, HashMap

먼저 모든 객체의 상위 타입인 Object에서 equals()는 단순히 == 동일성을 비교합니다.
그래서 equals()를 오버라이딩 하지않으면 ==과 다르지 않습니다.

String과 같은 랩퍼 클래스도 equals()를 오버라이딩해서 동일성이 아닌 동등성으로 비교할 수 있는 것입니다.

그렇다면 hashCode()는 왜 필요할까요?

일단 Object 클래스에서 hashCode에 대한 설명을 보면 HashMap에서 지원하는 것과 같이
Hash table 자료 구조에 이점을 주기 위함이라고 되어 있습니다.

일단 가장 기본적으로 알아두어야 하는 것은,
HashMap과 같은 자료구조에 key로 사용되는 객체에 대해서는 무조건 equals()hashCode()가 꼭 같이 오버라이딩 되어야합니다.

HashMap에 key와 value를 저장할 때, 키를 식별할 때 hash값이 같고! 키가 동일하거나(==), 키가 동등한지(equals())로 구별합니다.
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
hash는 무조건 같아야함을 의미합니다.

그래서 객체는 equals()가 true라면 항상 같은 hashCode() 값을 반환해야하는 것입니다.

하지만 반대로 hashCode() 값이 같다고해서, equals()가 항상 true임을 보장하지는 않습니다.

Object 클래스의 명세에서 hashCode() 규약

첫 번째, equals 비교에 사용되는 정보가 변경되지 않았다면,
그 객체의 hashCode 메서드는 몇 번을 호출하더라도 애플리케이션이 실행되는 동안 매번 같은 값을 반환해야 한다.
단, 애플리케이션을 다시 실행한다면 값이 달라져도 상관없다.

두 번째, equals(Object)의 결과가 두 객체를 같다고 판단했다면,
두 객체의 hashCode는 같은 값을 반환해야 한다.

세 번째, equals(Object)의 결과가 두 객체를 다르다고 판단했더라도,
두 객체의 hashCode 가 서로 다른 값을 반환할 필요는 없다. 
단, 다른 객체에 대해서는 다른 값을 반환해야 해시 테이블(hash table)의 성능이 좋아진다.

그래서 결론으로 객체의 equals()hashCode()를 함께 오버라이딩할 때,
사용되는 필드에 대해서 꼭 확인해야 합니다.

@equalsAndHashCode 롬복 어노테이션을 활용하면 static과 @trasient 붙은 필드를 제외하고 메서드를 오버라이딩해줍니다.

References

https://woodcock.tistory.com/24?category=978592
더 자세한 이해는 이펙티브 자바를 참고하시는 편이 좋을것 같습니다.