Java

equals / hashCode 오버라이딩

코딩스토리 2023. 12. 5. 21:04

equals 메소드


equals 메소드는 기본적으로 2개의 객체가 동일한지 검사하기 위해 사용. 2개의 객체가 참조하는 것이 동일한지를 확인하는 것이며, 이는 동일성(Identity)을 비교하는 것. 동일한 메모리 주소일 경우에만 동일한 객체가 된다.

하지만 프로그래밍을 하다보면 동일한 객체가 메모리 상에 여러 개 띄워져있는 경우가 있다. 해당 객체는 서로 다른 메모리에 띄워져있으므로 동일한(Identity) 객체가 아니다. 하지만 프로그래밍 상으로는 같은 값을 지니므로 같은 객체로 인식되어야 하는데, 이러한 동등성(Equality)를 위해 우리는 값으로 객체를 비교하도록 equals 메소드를 오버라이딩해주는 것이다.

 

 

 

hashCode 메소드


hashCode 메서드는 객체의 주소 값을 이용해서 해싱(hashing) 기법을 통해 해시 코드를 만든 후 반환한다.기 때문에 서로 다른 두 객체는 같은 해시 코드를 가질 수 없게 된다. 그래서 해시코드는 객체의 지문이라고도 한다.
엄밀히 말하면 해시코드는 주소값은 아니고, 주소값으로 만든 고유한 숫자값이라고 하는게 옳다.

 

 

 

equals 와 hashCode 의 관계


hashCode 를 equals 와 함께 재정의하지 않으면 코드가 예상과 다르게 작동하는 위와 같은 문제를 일으킨다.
정확히 말하면 hash 값을 사용하는 Collection(HashSet, HashMap, HashTable)을 사용할 때 문제가 발생한다.

 

 

가장 먼저 데이터가 추가된다면, 그 데이터의 hashCode()의 리턴 값을 컬렉션에 가지고 있는지 비교한다.
만일 해시코드가 같다면 그제서야 다음으로 equals() 메서드의 리턴 값을 비교하게 되고, true이면 논리적으로 같은 객체라고 판단한다.

 

hashcode()를 재정의 하지 않으면 같은 값 객체라도 해시값이 다를 수 있다. 따라서 HashTable에서 해당 객체가 저장된 버킷을 찾을 수 없다.
반대로 equals()를 재정의하지 않으면 hashcode()가 만든 해시값을 이용해 객체가 저장된 버킷을 찾을 수는 있지만 해당 객체가 자신과 같은 객체인지 값을 비교할 수 없기 때문에 null을 리턴하게 된다. 따라서 역시 원하는 객체를 찾을 수 없다.

 

hashCode 를 만드는 해시 함수를 equals 메소드를 재정의할 때 사용한 필드와 같은 필드를 사용하자.
만약 객체는 같은 해시 코드를 가지게 되면 전부 같은 버킷에 해시되므로 해시 테이블은 아주 긴 링크드 리스트가 많이 생기게 될 것.
해시 테이블(hash table)의 평균 시간 복잡도는 O(1)이고, 최악의 로직을 가진 해시 테이블의 시간 복잡도는 O(n) 이다. 만약 이 해시 테이블이 해시 충돌(hash collision) 해결을 해시 체이닝(hash chaining) 방식으로 구현했다면, 실제 링크드 리스트(linked list) 처럼 동작한다.


hashCode를 재정의 하지 않았을 경우 생기는 문제점
   - 같은 값을 가진 객체가 서로 다른 해시값을 갖게 될 수 있다.
   - 특히 HashMap의 key 값으로 해당 객체를 사용할 경우 저장된 버킷을 찾을 수 없다.