[Java] ๐Ÿชบ hashCode๋Š” ํ•ญ์ƒ ๊ณ ์œ ํ• ๊นŒ?

Sangho Hanยท2025๋…„ 6์›” 22์ผ
3

โ˜•๏ธย Java

๋ชฉ๋ก ๋ณด๊ธฐ
20/20
post-thumbnail

๐Ÿ“Œ hashCode

Java์—์„œ์˜ ํ•ด์‹œ ์ฝ”๋“œ๋Š” ๊ฐ์ฒด๋ฅผ ํ•ด์‹œ ๊ธฐ๋ฐ˜ ์ž๋ฃŒ๊ตฌ์กฐ์—์„œ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์„ฑ๋˜๋Š” ์ •์ˆ˜ ๊ฐ’์ด๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ํ•ด์‹œ ์ฝ”๋“œ ์ž์ฒด๊ฐ€ ๊ฒน์น˜๋Š” ๊ฒฝ์šฐ๋Š” ์ž์ฃผ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋‚˜, ๊ทธ๋ ‡๋‹ค๊ณ  ํ•ด์‹œ ์ฝ”๋“œ๊ฐ€ ๊ณ ์œ ํ•˜๋‹ค ๋ผ๊ณ  ๋งํ•  ์ˆ˜๋Š” ์—†๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์ด์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.


๐Ÿ“Œ hashCode๊ฐ€ ๊ณ ์œ ํ•˜์ง€ ์•Š์€ ์ด์œ 

1. hashCode๋Š” 32๋น„ํŠธ int ๊ฐ’์ด๋‹ค

Java์—์„œ์˜ hashCode๋Š” int ์ •์ˆ˜ํ˜•์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค. ๋•Œ๋ฌธ์— ๊ฐ’์˜ ๋ฒ”์œ„๋Š” ์•ฝ -21์–ต ~ +21์–ต์œผ๋กœ ์•ฝ 43์–ต ๊ฐ€์ง€๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰, ๋ฌดํ•œํ•˜์ง€ ์•Š์€ ์œ ํ•œํ•œ ๊ฐ’์ด๋ผ๋Š” ๊ฒƒ์ด๋‹ค.

๋‹จ์ˆœํ•˜๊ฒŒ JVM ๋‚ด ๊ฐ์ฒด ์ˆ˜๊ฐ€ ์ด๋ณด๋‹ค ๋งŽ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ,
์ˆ˜๋งŽ์€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ์ด 43์–ต ๊ฐ€์ง€ hashCode ๊ฐ’ ์ค‘ ํ•˜๋‚˜์— ๋งคํ•‘๋˜๋ฏ€๋กœ ์ถฉ๋Œ์€ ์ˆ˜ํ•™์ ์œผ๋กœ ํ•„์—ฐ์ ์ด๋‹ค.

ํ•ด์‹ฑ์˜ ์„ธ๊ณ„์—์„œ๋Š” ์ด๋ฅผ ๋น„๋‘˜๊ธฐ์ง‘ ์›๋ฆฌ(Pigeonhole principle) ๋กœ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋ฅธ ๊ฐ์ฒด์ž„์—๋„ ํ•ด์‹œ ์ฝ”๋“œ๊ฐ€ ๋™์ผํ•œ ๊ฒฝ์šฐ๋ฅผ ํ•ด์‹œ์ถฉ๋Œ์ด๋ผ๊ณ  ๋ถ€๋ฅด๋ฉฐ, ์ด๋Ÿฌํ•œ ์ถฉ๋Œ์„ ์ตœ์†Œํ™” ํ•˜๋Š” ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

๋น„๋‘˜๊ธฐ์ง‘ ์›๋ฆฌ

๋น„๋‘˜๊ธฐ์ง‘ ์›๋ฆฌ๋ž€,
N๊ฐœ์˜ ๋น„๋‘˜๊ธฐ ์ง‘์— M๋งˆ๋ฆฌ์˜ ๋น„๋‘˜๊ธฐ๋ฅผ ๋„ฃ์œผ๋ ค๊ณ  ํ•  ๋•Œ M > N์ด๋ฉด ์–ด๋–ค ๋น„๋‘˜๊ธฐ ์ง‘์—๋Š” ํ•„์—ฐ์ ์œผ๋กœ ๋น„๋‘˜๊ธฐ๊ฐ€ 2๋งˆ๋ฆฌ ์ด์ƒ ๋“ค์–ด๊ฐ„๋‹ค๋Š” ์ˆ˜ํ•™์ ์ธ ์›๋ฆฌ์ด๋‹ค.

์ฆ‰, 11๋งˆ๋ฆฌ์˜ ๋น„๋‘˜๊ธฐ๋ฅผ 10๊ฐœ์˜ ์ง‘์— ๋„ฃ์œผ๋ ค๊ณ  ํ•  ๋•Œ ์•„๋ฌด๋ฆฌ ์ž˜ ๋ถ„๋ฐฐํ•˜๋”๋ผ๋„ 1๊ฐœ์˜ ์ง‘์—๋Š” 2๋งˆ๋ฆฌ ์ด์ƒ์˜ ๋น„๋‘˜๊ธฐ๊ฐ€ ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

hashCode๋ฅผ intํ˜•์œผ๋กœ ๋งŒ๋“  ์ด์œ ?

ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ int๊ฐ€ ์•„๋‹Œ long์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋ฉด ํ•ด์‹œ ์ถฉ๋Œ์ด ๋” ์ค„์–ด๋“ค์ง€ ์•Š์„๊นŒ? ์™œ int ํ˜•์œผ๋กœ ๋งŒ๋“  ๊ฒƒ์ผ๊นŒ?

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด long์œผ๋กœ ๋งŒ๋“ ๋‹ค๊ณ  ํ•ด์„œ, ํšจ์œจ์„ฑ์ด ๋†’์•„์ง„๋‹ค๊ณ  ๋ณด์žฅํ•  ์ˆ˜ ์—†๋‹ค. ์ด์œ ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

ํ•ด์‹œ ๊ธฐ๋ฐ˜ ์ปฌ๋ ‰์…˜์˜ ํšจ์œจ์„ฑ

  • HashMap, HashSet, Hashtable ๊ฐ™์€ ์ž๋ฃŒ๊ตฌ์กฐ๋“ค์€ ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฒ„ํ‚ท์ด๋ผ๋Š” ๊ฐœ๋…์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์ด๋Š” ๋ฐฐ์—ด๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.
  • ๋ฐฐ์—ด์˜ ์ธ๋ฑ์Šค๋ฅผ hashCode % capacity(๋ฐฐ์—ด size) ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๊ณ„์‚ฐํ•œ๋‹ค.
  • Java์—์„œ์˜ ๋ฐฐ์—ด ํฌ๊ธฐ๋Š” intํ˜•์œผ๋กœ ์ œํ•œ๋˜์–ด ์žˆ๋‹ค.
  • ๋•Œ๋ฌธ์— ๋งŒ์•ฝ ํ•ด์‹œ ์ฝ”๋“œ๊ฐ€ long์ด๋ผ๋ฉด, ์ธ๋ฑ์Šค๋ฅผ ๊ณ„์‚ฐํ•  ๋•Œ ์ถ”๊ฐ€ ์—ฐ์‚ฐ(long โ†’ int ๋ณ€ํ™˜ ๋“ฑ)์ด ํ•„์š”ํ•ด ํšจ์œจ์„ฑ์ด ์˜คํžˆ๋ ค ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ

  • ์ง€๊ธˆ๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ, 1990๋…„๋Œ€ ์ดˆ๋ฐ˜ Java ์„ค๊ณ„ ๋‹น์‹œ์—๋Š” ๋ฉ”๋ชจ๋ฆฌ์™€ CPU ๋น„์šฉ์— ํ›จ์”ฌ ๋ฏผ๊ฐํ–ˆ๋‹ค.
  • ๋งŒ์•ฝ long(64๋น„ํŠธ)์„ hashCode๋กœ ์“ฐ๋ฉด ํ•ด์‹œ ํ…Œ์ด๋ธ” ๋‚ด๋ถ€์—์„œ long ์—ฐ์‚ฐ์ด ๋งŽ์•„์ง€๊ณ , ํ•„์š” ์ด์ƒ ํฐ ๊ฐ’์œผ๋กœ index๋ฅผ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ๋‚ญ๋น„๊ฐ€ ์‹ฌํ•ด์ ธ int๋กœ ์ •ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

2. hashCode๋Š” ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ ๊ธฐ๋ฐ˜์ด ์•„๋‹ˆ๋‹ค

๋งŒ์•ฝ hashCode == ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ ์˜€๋‹ค๋ฉด, ์ด๋Š” ๊ฐ์ฒด๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ณ ์œ ํ•œ ๊ฐ’์ด ๋งž์œผ๋ฏ€๋กœ ํ•ด์‹œ ์ฝ”๋“œ๊ฐ€ ๊ณ ์œ ํ•  ์ˆ˜๋„ ์žˆ๊ฒ ๋‹ค.

ํ•˜์ง€๋งŒ hashCode๋Š” ๊ฐ์ฒด์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์™€ ๋‹ค๋ฅด๋‹ค. JVM ๋‚ด๋ถ€ ๊ตฌํ˜„ ๋ฐฉ์‹์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒ ์ง€๋งŒ, ํ˜„์žฌ๋Š” ๋Œ€๋ถ€๋ถ„ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์™€ ์ „ํ˜€ ๊ด€๋ จ์ด ์—†๋‹ค.

๋˜ํ•œ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค ํ•˜๋”๋ผ๋„, ๊ฐ์ฒด ๊ฐœ์ˆ˜๊ฐ€ 43์–ต ๊ฐœ๋ฅผ ๋„˜์–ด๊ฐ„๋‹ค๋ฉด ๋น„๋‘˜๊ธฐ์ง‘ ์›๋ฆฌ์— ์˜ํ•ด์„œ ์ถฉ๋Œ์ด ํ•„์—ฐ์ ์œผ๋กœ ๋ฐœ์ƒํ•œ๋‹ค.


๐Ÿ“Œ ํ…Œ์ŠคํŠธ

import java.util.ArrayList;
import java.util.List;

public class HashCodeCollisionTest {
    public static void main(String[] args) {
        List<Integer> seenHashCodes = new ArrayList<>();
        int collisionCount = 0;
        int maxAttempts = 1000000;

        for (int i = 0; i < maxAttempts; i++) {
            Object obj = new Object();
            int hashCode = obj.hashCode();

            if (seenHashCodes.contains(hashCode)) {
                collisionCount++;
                System.out.println((i + 1) + "๋ฒˆ์งธ ์‹œ๋„");
                System.out.println("์ถฉ๋Œ hashCode: " + hashCode);
                System.out.println();
            } else {
                seenHashCodes.add(hashCode);
            }
        }

        if (collisionCount == 0) {
            System.out.println("์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. (์‹œ๋„ ์ˆ˜: " + maxAttempts + ")");
        } else {
            System.out.println("์ด ์ถฉ๋Œ ๋ฐœ์ƒ ํšŸ์ˆ˜: " + collisionCount);
        }
    }
}

์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ , ๋ฆฌ์ŠคํŠธ์— ๋„ฃ์€ ํ›„ ๋™์ผํ•œ ํ•ด์‹œ ์ฝ”๋“œ๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•œ๋‹ค๋ฉด ์ถœ๋ ฅํ•˜๋Š” ํ˜•ํƒœ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜์˜€๋‹ค.

์›๋ž˜๋Š” HashMap, HashSet๋ฅผ ํ™œ์šฉํ•˜๋ ค ํ–ˆ๋Š”๋ฐ, ์ด๋Š” ํ•ด์‹œ ์ปฌ๋ ‰์…˜์ด๋ผ -> ํ•ด์‹œ์ฝ”๋“œ ์ž์ฒด๋กœ๋งŒ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋‚ด๋ถ€์ ์ธ ํ•ด์‹œ ํ…Œ์ด๋ธ” ์ƒ์—์„œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ArrayList๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

๊ฒฐ๊ณผ

...

987463๋ฒˆ์งธ ์‹œ๋„
์ถฉ๋Œ hashCode: 1999539787

993518๋ฒˆ์งธ ์‹œ๋„
์ถฉ๋Œ hashCode: 1845922248

994245๋ฒˆ์งธ ์‹œ๋„
์ถฉ๋Œ hashCode: 1479783205

994730๋ฒˆ์งธ ์‹œ๋„
์ถฉ๋Œ hashCode: 2063331329

์ด ์ถฉ๋Œ ๋ฐœ์ƒ ํšŸ์ˆ˜: 232

1๋งŒ, 10๋งŒ ๋ฒˆ ๊นŒ์ง€๋Š” ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์œผ๋‚˜, 100๋งŒ ๋ฒˆ์œผ๋กœ ํšŸ์ˆ˜๋ฅผ ๋Š˜๋ฆฌ๋‹ˆ ์ถฉ๋Œ ํšŸ์ˆ˜๊ฐ€ ํ˜„์ €ํ•˜๊ฒŒ ๋Š˜์–ด๋‚ฌ๋‹ค.


๐Ÿ“Œ hashCode๊ฐ€ ๊ณ ์œ ํ•˜์ง€ ์•Š์•„๋„ ๊ดœ์ฐฎ์€ ์ด์œ 

์—ฌ๊ธฐ๊นŒ์ง€ Java์—์„œ์˜ ํ•ด์‹œ ์ฝ”๋“œ๋Š” ๊ณ ์œ ํ•˜์ง€ ์•Š์Œ์„ ์•Œ์•„๋ณด์•˜๋‹ค. ๊ณ ์œ ํ•˜์ง€ ์•Š๋‹ค๋ฉด ๋‹ค๋ฅธ ๊ฐ์ฒด์ž„์„ ํ™•์ธํ•  ์ˆ˜๊ฐ€ ์—†๊ฒŒ ๋ ํ…๋ฐ, ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€๋Š” ์•Š์„๊นŒ?

์„ค๊ณ„์ ์œผ๋กœ hashCode ์ถฉ๋Œ์„ ํ—ˆ์šฉํ•œ๋‹ค

ํ•ด์‹œ ์ปฌ๋ ‰์…˜์—์„œ ๋™๋“ฑ ๊ฐ์ฒด๋ฅผ ํŒ๋ณ„ํ•  ๋•Œ, ์œ„์™€ ๊ฐ™์€ ๋กœ์ง์„ ๊ฑฐ์นœ๋‹ค.

  1. ํ•ด์‹œ ์ฝ”๋“œ๊ฐ€ ๊ฐ™์€๊ฐ€?
  2. equals()๊ฐ€ true์ธ๊ฐ€?

์ฆ‰, ๋‹ค๋ฅธ ๊ฐ์ฒด๋ผ๋ฆฌ ๊ฐ™์€ ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋˜๋”๋ผ๋„, equals()์—์„œ false๊ฐ€ ๋‚˜์˜ค๊ฒŒ ๋˜๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด๋‹ค.

๋ฌผ๋ก , ํ•ด์‹œ ์ฝ”๋“œ ์ž์ฒด๋กœ๋งŒ ๋น„๊ต๋ฅผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, ์ด๋Š” ํ”์น˜ ์•Š๋‹ค.

Java์˜ hashCode() ์„ค๊ณ„ ์›์น™

โ€œequals๊ฐ€ ๊ฐ™์œผ๋ฉด hashCode๋„ ๊ฐ™์•„์•ผ ํ•˜์ง€๋งŒ, equals๊ฐ€ ๋‹ค๋ฅด๋ฉด hashCode๋Š” ๊ฐ™์„ ์ˆ˜๋„ ์žˆ๋‹ค.โ€

์ฆ‰, ์ถฉ๋Œ์€ ์ด๋ฏธ ์˜ˆ์ƒ๋œ ์ƒํ™ฉ์ด๋ฉฐ, equals()๋กœ ์ตœ์ข… ๊ตฌ๋ถ„ํ•˜๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ๋‹ค.

์ค‘์š”ํ•œ ๊ฒƒ์€ ์ถฉ๋Œ์„ ์ตœ์†Œํ™” ํ•˜๋Š” ๋ฐฉ๋ฒ•(์ข‹์€ ํ•ด์‹œ ํ•จ์ˆ˜ ๋“ฑ)๊ณผ ํ•ด์‹œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ํšจ์œจ์ ์œผ๋กœ ๋Œ€์ฒ˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์ผ ๊ฒƒ์ด๋‹ค.

๋‹ค์Œ ๊ธ€์—์„œ๋Š” ํ•ด์‹œ ์ถฉ๋Œ์— ๋Œ€ํ•ด์„œ ๋‹ค๋ฃจ์–ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.


์ฐธ๊ณ ํ•œ ๋ธ”๋กœ๊ทธ 1
์ฐธ๊ณ ํ•œ ๋ธ”๋กœ๊ทธ 2

profile
์•ˆ๋…•ํ•˜์„ธ์š”. ๋น„์ฆˆ๋‹ˆ์Šค๋ฅผ ์ดํ•ดํ•˜๋Š” ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž, ํ•œ์ƒํ˜ธ์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€