반응형
Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags
more
Archives
Today
Total
관리 메뉴

안드로이드 개발자 노트

[이펙티브 코틀린] Item41. hashCode의 규약을 지켜라 본문

Kotlin/이펙티브 코틀린

[이펙티브 코틀린] Item41. hashCode의 규약을 지켜라

어리둥절범고래 2024. 1. 13. 19:01
반응형

해시 테이블은 각 요소에 숫자를 할당하는 함수가 필요합니다.

이 함수를 해시 함수라고 부르며, 같은 요소라면 항상 같은 숫자를 리턴합니다.
해시 함수는 빠르고 충돌이 적을 수록 좋습니다.

 

 

가변성과 관련된 문제

 

요소가 추가될 때만 해시 코드를 계산합니다.
요소가 변경되어도 해시 코드는 계산되지 않으며, 버킷 재배치도 이루어지지 않습니다.
그래서 기본적인 LinkedHashSet와 LinkedHashMap의 키는 한 번 추가한 요소를 변경할 수 없습니다.
세트와 맵의 키로 mutable 요소를 사용하면 안되고, 사용하더라도 요소를 변경해서는 안됩니다.

data class FullName(
    var name: String,
    var surname: String
)

val person = FullName("Maja", "Markiewicz")
val s = mutableSetOf<FullName>()
s.add(person)
person.surname = "Moskala"
print(person) // FullName(name=Maja, surnam=Moskala)
print(person in s) // false
print(s.first() == person) // true

 

 

 

hashCode의 규약

 

hashCode는 명확한 규약이 있습니다.

 

  • 어떤 객체를 변경하지 않았다면, hashCode는 여러 번 호출해도 그 결과가 항상 같아야 한다.
  • equals 메서드의 실행 결과도 두 객체가 같다고 나온다면, hashCode 메서드의 호출 결과도 같다고 나와야 한다.

두 번째 요구 사항은 'hashCode는 equals와 같이 일관성 있는 동작을 해야 한다'는 것을 의미합니다.

즉, 같은 요소는 반드시 같은 해시 코드를 가져야 하며, 그렇지 않으면 컬렉션 내부에 요소가 들어 있는지 제대로 확인하지 못하는 문제가 발생할 수 있습니다.

그래서 코틀린은 equals 구현을 오버라이드할 때, hashCode도 함께 오버라이드하는 것을 추천합니다.

 

 

hashCode 구현하기

 

equals를 따로 정의했다면, 반드시 hashCode도 함께 정의해 줘야 합니다.

equals를 따로 정의하지 않았다면, 정당한 이유가 없는 이상 hashCode를 따로 정의하지 않는 것이 좋습니다.

hashCode는 기본적으로 equals에서 비교에 사용되는 프로퍼티를 기반으로 해시코드를 만들어야 합니다.

다음은 일반적인 equals와 hashCode의 구현 예입니다.

class DateTime(
    private var millis: Long = 0L,
    private var timeZone: TimeZone? = null
) {
    private var asStringCache = ""
    private var changed = false
    
    override fun equals(other: Any?): Boolean =
        other is DateTime &&
            other.millis == millis &&
            other.timeZone == timeZone
           
    override fun hashCode(): Int {
        var result = millis.hashCode()
        result = result * 31 + timeZone.hashCode() // 관례적으로 31을 사용한다.
        return result
    }   
}

hashCode를 구현할 때 가장 중요한 규칙은 '언제나 equals와 일관된 결과가 나와야 한다'입니다.

같은 객체라면 언제나 같은 값을 리턴하게 만들어야 합니다.

반응형