공부/이펙티브코틀린

아이템 41 - hashCode 의 규약을 지켜라

띵커베르 2024. 8. 1. 23:24
728x90

hashCode 함수는 해시 테이블을 구축할 때 사용된다.

  • 임의의 길이를 가진 데이터를 고정된 길이의 데이터로 변환(매핑)하는 것
  • 이러한 과정을 해싱 한다고 하며, 해시함수에 얻어진 값을 보통 다이제스트(digest)라고 한다.
  • 키 값의 무한성과 해시 함수 출력 값의 유한성 때문에 충돌이 일어날 수 있다.

 

가변성과 관련된 문제:

요소가 추가될 때만 해시 코드를 계산합니다.
요소가 변경되어도 해시 코드는 계산되지 않으며, 버킷 재배치도 이루어지지 않습니다.
그래서 기본적인 LinkedHashSet 와 LinkedHashMap 의 키 는 한번 추가한 요소를 변경할 수 없습니다.

=> 해시 기반 컬렉션에서는 키로 사용되는 객체가 불변이어야 한다. 키 객체가 변경 가능한 속성을 가진다면, 객체를 해시 테이블에 추가한 후에 그 속성을 변경하지 않아야 한다.

 

 

  • hashCode 메서드의 규약:
    • 일관성: 같은 객체에 대해 여러 번 호출해도 같은 값을 반환해야 합니다. 객체의 상태가 변경되지 않는 한, hashCode는 항상 같은 값을 반환해야 합니다.
    • 동일성: 두 객체가 equals 메서드로 비교했을 때 같다면, 같은 hashCode를 반환해야 합니다. a.equals(b) == true이면 a.hashCode() == b.hashCode()도 true여야 합니다.
    • 동일하지 않음: 두 객체가 equals 메서드로 비교했을 때 다르다고 해서 반드시 다른 hashCode를 반환할 필요는 없습니다. 하지만 다른 객체에 대해서는 가능한 한 다른 hashCode 값을 반환하는 것이 좋습니다. a.equals(b) == false이면 a.hashCode() != b.hashCode()가 반드시 참일 필요는 없지만, 다르게 구현하는 것이 성능에 유리합니다.
  • hashCode 메서드 구현 시 주의사항:
    • 중요한 필드 사용: 객체의 중요한 필드를 사용하여 고유한 해시코드를 생성합니다.
    • 불변성 보장: 객체의 상태가 변경되지 않는 한, 같은 해시코드를 반환하도록 보장합니다.
    • 충돌 최소화: 서로 다른 객체가 같은 해시코드를 가질 확률을 최소화하도록 해시코드를 생성합니다.
  • hashCode 메서드 구현 예시:
data class Person(val name: String, val age: Int) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other == null || javaClass != other.javaClass) return false

        other as Person
        return name == other.name && age == other.age
    }

    override fun hashCode(): Int {
        var result = name.hashCode()
        result = 31 * result + age
        return result
    }
}

 

 

 

hashCode 를 구현할 때는 equals와 일관된 결과가 나와야 한다.

728x90