Prime Number 17

2025. 4. 23. 17:12High Level Programming Language/Learning the Java Language

자바에서 hashCode() 메서드 오버라이딩 시 흔히 사용되는 초기값 17 역시 단순한 임의의 숫자가 아니라, 컴퓨터 과학적·실무적 맥락에서 깊은 의미와 역할을 갖습니다.

 

🎯 핵심 요약

hashCode()의 초기값으로 17을 사용하는 이유는, 해시코드 조합의 출발점을 예측 불가능하게 만들고, 필드 해시코드들의 충돌 가능성을 낮추기 위한 시드(seed) 역할을 하기 때문입니다.

 

📌 1. 해시코드에서 초기값의 역할은 무엇인가?

✅ 해시코드 누적 합산 방식

자바에서 다중 필드를 해시코드로 조합할 때는 다음과 같은 방식이 일반적입니다:

int result = INITIAL;          // 초기값
result = 31 * result + field1; // 누적
result = 31 * result + field2;
...

✅ 초기값의 목적

  • 항상 같은 필드 조합이라도, 초기값이 다르면 해시코드가 달라짐
  • 초기값은 일종의 "시작점 시드(seed)" 역할을 하여 충돌 가능성을 줄이는 데 기여

 

🔢 2. 왜 하필 17인가?

✅ 이유 1: 소수(Prime Number)

  • 17소수(prime number)입니다.
  • 해시코드 계산에서 소수를 사용하면, 특정 필드 조합이 비슷해도 충돌 가능성을 줄이는 효과가 있습니다.
  • 필드 간 곱셈 인자(31)뿐만 아니라, 초기값 또한 소수를 사용함으로써 전체적으로 해시 함수의 품질을 높임

✅ 이유 2: 작은 수이면서도 너무 작지 않음

  • 0, 1, 2, 7 등 너무 작은 수는 해시 분산 효과가 약하며, 패턴화된 결과를 만들 수 있습니다.
  • 17은 적당한 크기의 정수로서, 성능 오버헤드 없이 예측 불가능성을 제공합니다.

✅ 이유 3: Effective Java의 표준 제안

Joshua Bloch의 저서 『Effective Java』에서는 다음의 초기값을 제안합니다:

Choose a nonzero odd number for initial result, preferably a prime like 17.
  • 이는 오라클, 구글, 스프링, 안드로이드 등 수많은 코드베이스에서 채택한 사실상의 자바 해시코드 표준 관례입니다.

 

📘 예시: equals()와 함께 쓰이는 전형적인 hashCode()

@Override
public int hashCode() {
    int result = 17;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    result = 31 * result + age;
    return result;
}
  • 17 → 해시 누적의 출발점 (seed)
  • 31 → 각 필드의 영향력을 차등 부여하기 위한 가중치 (weight)

 

🧠 3. 숫자 선택에 있어 고려된 조건

조건 의미 17이 적합한 이유
소수 여부 충돌 확률 감소 ✅ 소수 (prime)
홀수 여부 2로 나누어지는 정수 생성 방지 ✅ 홀수
적절한 크기 너무 작지도 크지도 않아야 함 ✅ 적당한 크기
관례 Java 커뮤니티에서 널리 사용됨 ✅ 표준 관례

 

 

🚫 초기값으로 0을 사용하면 안 되는 이유?

int result = 0; // 초기값을 0으로 사용
result = 31 * result + field.hashCode(); // 0 * 31 == 0, 필드 해시만 반영
  • 첫 필드의 해시코드가 전체 결과에 너무 지배적으로 작용함
  • 다수의 객체가 동일한 해시코드를 갖게 될 위험 증가
  • 즉, 초기값은 필드 조합에 의한 해시 다양성 확보를 위한 필수 요소

 

✅ 결론: 왜 17인가?

항목 설명
소수(Prime) 해시 분산성과 충돌 회피에 유리
홀수(Odd) 짝수 연산으로 인한 패턴화 방지
작은 정수 계산 성능에 부담 없음
표준 관례 Effective Java, 자바 표준 라이브러리에서 채택

 

📌 요약: 17은 해시코드 설계의 품질, 예측불가성, 연산 효율성, 표준성 모두를 고려해 경량 고품질 초기값으로 이상적인 수입니다.

 

🔍 참고 사항

  • 해시 충돌 분포 시뮬레이션 (해시 함수 성능 실험)
  • Objects.hash() 내부 구현 분석
  • record 타입에서 hashCode 자동 생성 구조
  • HashMap의 hash 분산 구조 (spread() 함수)