Item 11. hashCode

equalsλ₯Ό μž¬μ •μ˜ν•˜λ €κ±°λ“  hashCode도 μž¬μ •μ˜ν•˜λΌ

μ•„μ΄ν…œ 10μ—μ„œ equalsλ₯Ό μž¬μ •μ˜ν•  λ•Œ hashCode도 μž¬μ •μ˜ν•΄μ•Ό ν•œλ‹€κ³  μ–ΈκΈ‰ν–ˆλ‹€. Object λͺ…μ„Έμ—λŠ” μ•„λž˜μ™€ 같이 μ •μ˜λ˜μ–΄ μžˆλ‹€.

  • equals 비ꡐ에 μ‚¬μš©λ˜λŠ” 정보가 λ³€κ²½λ˜μ§€ μ•ŠμœΌλ©΄, hashCode λ°˜ν™˜ 값도 항상 κ°™μ•„μ•Ό 함(일관성)

  • equalsκ°€ 두 객체λ₯Ό κ°™λ‹€κ³  νŒλ‹¨ν•˜λ©΄, 두 객체의 hashCodeλŠ” 같은 값을 λ°˜ν™˜ν•΄μ•Ό 함

  • equalsκ°€ 두 객체λ₯Ό λ‹€λ₯΄λ‹€κ³  νŒλ‹¨ν•΄λ„, 두 객체의 hashCodeκ°€ μ„œλ‘œ λ‹€λ₯Έ 값을 λ°˜ν™˜ν•  ν•„μš”λŠ” μ—†μŒ(단, λ‹€λ₯Έ 객체에 λŒ€ν•΄μ„œλŠ” λ‹€λ₯Έ 값을 λ°˜ν™˜ν•΄μ•Ό μ„±λŠ₯이 쒋아짐)

μž¬μ •μ˜λ₯Ό μ˜¬λ°”λ₯΄κ²Œ ν•˜μ§€ μ•ŠμœΌλ©΄ HashMap / HashSet 같은 Hash 기반 μ»¬λ ‰μ…˜μ—μ„œ μ œλŒ€λ‘œ λ™μž‘ν•˜μ§€ μ•Šκ²Œ λœλ‹€.

hashCode μž¬μ •μ˜ 방법

쒋은 hashCodeλ₯Ό μž‘μ„±ν•˜λŠ” 방법은 μ•„λž˜μ™€ κ°™λ‹€. μš°μ„  μ£Όμ˜ν•΄μ•Όν•  뢀뢄은 equalsμ—μ„œ μ‚¬μš©ν•˜λŠ” ν•„λ“œλ“€κ³Ό λ™μΌν•œ ν•„λ“œλ“€μ„ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€λŠ” 것이닀.

  1. int λ³€μˆ˜ resultλ₯Ό μ„ μ–Έν•œ ν›„ κ°’ c둜 μ΄ˆκΈ°ν™”

  2. ν•΄λ‹Ή 객체의 각 핡심 ν•„λ“œμ— λŒ€ν•΄ μ•„λž˜μ™€ 같이 μˆ˜ν–‰ν•˜μ—¬ ν•΄μ‹œμ½”λ“œ cλ₯Ό 계산

    • κΈ°λ³Έ νƒ€μž…: Type.hashCode(f) μˆ˜ν–‰

    • μ°Έμ‘° νƒ€μž…: μž¬κ·€μ μœΌλ‘œ hashCodeλ₯Ό ν˜ΈμΆœν•˜λ©°, μ•„λž˜μ™€ 같은 κ·œμΉ™μœΌλ‘œ 계산

      • null: 0

      • λ°°μ—΄: Arrays.hashCodeλ₯Ό μ‚¬μš©

      • 핡심 ν•„λ“œ: 핡심 ν•„λ“œμ˜ hashCodeλ₯Ό μ‚¬μš©

      • ν•„λ“œκ°€ 핡심이 μ•„λ‹ˆλ©΄, ν•΄λ‹Ή ν•„λ“œμ˜ hashCodeλ₯Ό κ³„μ‚°ν•˜μ§€ μ•ŠμŒ

  3. κ³„μ‚°λœ ν•΄μ‹œμ½”λ“œ cλ₯Ό result에 더함(result = 31 * result + c)

Objects ν΄λž˜μŠ€μ—λŠ” μž„μ˜μ˜ 개수만큼 객체λ₯Ό λ°›μ•„ ν•΄μ‹œμ½”λ“œλ₯Ό κ³„μ‚°ν•΄μ£ΌλŠ” 정적 λ©”μ„œλ“œμΈ hashκ°€ μžˆλ‹€. μœ„μ˜ μš”κ΅¬μ‚¬ν•­μ„ μΆ©μ‘±ν•˜μ—¬ 잘 κ΅¬ν˜„λ˜μ–΄ μžˆμœΌλ―€λ‘œ, 이 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 κ°€μž₯ μ’‹μ§€λ§Œ 속도가 느리기 λ•Œλ¬Έμ— μ„±λŠ₯이 μ€‘μš”ν•œ μƒν™©μ—μ„œλŠ” 직접 κ΅¬ν˜„ν•˜λŠ” 것이 μ’‹λ‹€.

κ³±μ…ˆμ— 31을 μ‚¬μš©ν•˜λŠ” 이유

ν™€μˆ˜μ΄λ©΄μ„œ μ†Œμˆ˜μ΄κΈ° λ•Œλ¬ΈμΈλ°, 사싀 μ†Œμˆ˜λ₯Ό μ“°λŠ” μ΄μœ λŠ” λͺ…ν™•ν•˜μ§„ μ•Šκ³  μ „ν†΅μ μœΌλ‘œ μ‚¬μš©ν•˜λŠ” 값이라고 ν•œλ‹€. ν•˜μ§€λ§Œ 짝수λ₯Ό μ‚¬μš©ν•˜λ©΄μ„œ μ˜€λ²„ν”Œλ‘œμš°κ°€ λ°œμƒν•˜λ©΄ 정보λ₯Ό μžƒμ„ 수 있기 λ•Œλ¬Έμ— 짝수 값을 μ‚¬μš©ν•˜λŠ” 것은 쒋지 μ•Šλ‹€.

캐싱

μœ„μ—μ„œλ„ μ–ΈκΈ‰ν–ˆλ“―μ΄ ν•΄μ‹œμ½”λ“œλ₯Ό κ³„μ‚°ν•˜λŠ” 과정은 λΉ„μš©μ΄ 많이 λ“€ 수 μžˆλŠ” μž‘μ—…μ΄κΈ° λ•Œλ¬Έμ— ν•„λ“œμ— 값을 μΊμ‹±ν•˜λŠ” 방법이 μžˆλ‹€. ν•˜μ§€λ§Œ 이 방법은 ν•„λ“œκ°€ λ³€κ²½λ˜λ©΄ ν•΄μ‹œμ½”λ“œλ₯Ό λ‹€μ‹œ 계산해야 ν•˜λ―€λ‘œ, λΆˆλ³€ ν•„λ“œμ—λ§Œ μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.

class Test {
    private int hashCode;

    // ν˜ΈμΆœν•  λ•Œ μΊμ‹±λ˜λŠ” 지연 μ΄ˆκΈ°ν™”(lazy initialization) 기법 μ‚¬μš©
    @Override
    public int hashCode() {
        int result = hashCode;
        if (result == 0) {
            result = 31 * result + ...;
            hashCode = result;
        }
        return result;
    }
}

Last updated