Kotlin/코틀린 일반 클래스에서 hashCode() 제대로 구현하기

✨ 개요

일반 클래스에서 hashCode() 제대로 구현하기 — equals 계약, 충돌 최소화, 실전 레시피

data classequals/hashCode를 자동 생성하지만, 일반 클래스(비–data) 에서는 우리가 직접 hashCode()를 구현해야 할 때가 많습니다.
이 글은 언제/왜/어떻게 hashCode()를 구현해야 하는지, 실전 레시피와 주의점을 한 번에 정리합니다.


1. 요약


2 equals/hashCode 계약 (필수 이해)


3 언제 오버라이드해야 하나?

값 동등성이 목적이라면 data class가 기본 해답입니다. 다만 맞춤 동등성(일부 필드만 비교·계산 등)이 필요하면 일반 클래스에서 수동 구현이 낫습니다.


4. 기본 레시피(가장 흔한 패턴)

class User(
    val id: Long,
    val email: String?,
    val name: String,
    val flags: Int
) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is User) return false
        return id == other.id &&
               email == other.email &&
               name == other.name &&
               flags == other.flags
    }

    override fun hashCode(): Int {
        var result = id.hashCode()
        result = 31 * result + (email?.hashCode() ?: 0)
        result = 31 * result + name.hashCode()
        result = 31 * result + flags
        return result
    }
}

5. 타입별 처리 요령

타입 해시코드 계산
Int, Boolean, Char 그대로 사용 (true→1, false→0 권장)
Long id.hashCode()(JVM: (id xor (id ushr 32)).toInt())
Float value.toBits() 사용(예: 31*.. + value.toBits())
Double value.toBits().hashCode()
String, List, Set, Map 각 타입의 hashCode()내용 기반이라 그대로 사용 OK
배열(Array, IntArray 등) contentHashCode() / contentEquals() 필수 (기본 hashCode()참조 기반)
Enum 기본 hashCode() 사용
Nullable x?.hashCode() ?: 0
복합 객체 그 객체의 동등성/해시 구현에 신뢰 기반
override fun hashCode(): Int {
    var r = 1
    r = 31 * r + items.contentHashCode()   // ★ 배열은 contentHashCode
    r = 31 * r + (tag?.hashCode() ?: 0)
    return r
}

// 부동소수
val fBits = price.toBits()
result = 31 * result + fBits

6. 자바 유틸을 써도 되나? (Objects.hash)

JVM 한정으로 java.util.Objects.hash(a, b, c)를 써서 간단히 만들 수 있지만,


7. 흔한 실수 체크리스트


8. 확장 유틸

/** null-safe hash */
inline fun <T> T?.h(): Int = this?.hashCode() ?: 0

/** 31 곱셈 합성 */
fun combineHash(vararg parts: Int): Int {
    var r = 1
    for (p in parts) r = 31 * r + p
    return r
}

// 사용 예
override fun hashCode(): Int = combineHash(
    id.hashCode(),
    email.h(),
    name.hashCode(),
    flags
)


Related Posts