Study/Effective Java

์•„์ดํ…œ11. equals๋ฅผ ์žฌ์ •์˜ํ•˜๋ ค๊ฑฐ๋“  hashCode๋„ ์žฌ์ •์˜ํ•˜๋ผ

sw_develop 2023. 5. 7. 12:57

๐Ÿ“์ƒํ™ฉ

  • equals๋ฅผ ์žฌ์ •์˜ํ•œ ํด๋ž˜์Šค ๋ชจ๋‘์—์„œ hashCode๋„ ์žฌ์ •์˜ํ•ด์•ผ ํ•จ

 

์ด์œ 

  • hashCode ์ผ๋ฐ˜ ๊ทœ์•ฝ์„ ์–ด๊ธฐ๊ฒŒ ๋˜์–ด ํ•ด๋‹น ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ HashMap์ด๋‚˜ HashSet ๊ฐ™์€ ์ปฌ๋ ‰์…˜์˜ ์›์†Œ๋กœ ์‚ฌ์šฉํ•  ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋จ
  • ๊ทœ์•ฝ

 

๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๋ถ€๋ถ„

  • hashCode๋ฅผ ์ž˜๋ชป ์žฌ์ •์˜ํ–ˆ์„ ๋•Œ ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ์กฐํ•ญ์€ ๋‘ ๋ฒˆ์งธ์ž„
  • hashCode๋ฅผ ์žฌ์ •์˜ํ•˜์ง€ ์•Š์œผ๋ฉด ๋…ผ๋ฆฌ์  ๋™์น˜์ธ ๋‘ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ๋‘ ๋ฒˆ์งธ ๊ทœ์•ฝ์„ ์ง€ํ‚ค์ง€ ๋ชปํ•จ --> ์ฆ‰, ๋…ผ๋ฆฌ์ ์œผ๋กœ ๊ฐ™์€ ๊ฐ์ฒด๋Š” ๊ฐ™์€ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•จ

์˜ˆ์‹œ

Map<PhoneNumber, String> map = new HashMap<>();
map.put(new PhoneNumber(010, 1234, 5678), "java");

//PhoneNumber ํด๋ž˜์Šค์˜ equals๋ฅผ ์žฌ์ •์˜ํ–ˆ๋Š”๋ฐ hashCode๋ฅผ ์žฌ์ •์˜ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ
map.get(new PhoneNumber(010, 1234, 5678)); //์˜ˆ์ƒ ๊ฐ’ : java, ์‹ค์ œ ๊ฐ’ : null
  • PhoneNumber ํด๋ž˜์Šค์˜ hashCode๋ฅผ ์žฌ์ •์˜ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋…ผ๋ฆฌ์  ๋™์น˜์ธ ๋‘ ๊ฐ์ฒด๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— get ๋ฉ”์„œ๋“œ๋Š” ์—‰๋šฑํ•œ ํ•ด์‹œ ๋ฒ„ํ‚ท์— ๊ฐ€์„œ ๊ฐ์ฒด๋ฅผ ์ฐพ์œผ๋ ค ํ•จ
  • ๋งŒ์•ฝ ๋‘ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ™์€ ๋ฒ„ํ‚ท์— ๋‹ด์•˜๋”๋ผ๋„ get ๋ฉ”์„œ๋“œ๋Š” ์—ฌ์ „ํžˆ null์„ ๋ฐ˜ํ™˜ํ•จ
    • HashMap์€ ํ•ด์‹œ์ฝ”๋“œ๊ฐ€ ๋‹ค๋ฅธ ์—”ํŠธ๋ฆฌ๋ผ๋ฆฌ๋Š” ๋™์น˜์„ฑ ๋น„๊ต๋ฅผ ์‹œ๋„์กฐ์ฐจ ํ•˜์ง€ ์•Š๋„๋ก ์ตœ์ ํ™”๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž„

 

=> ์ด ๋ฌธ์ œ๋Š” ์ ์ ˆํ•œ hashCode ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ๋ฉด ํ•ด๊ฒฐ๋จ!

 

๐Ÿ“๋ฐฉ๋ฒ•

์˜ฌ๋ฐ”๋ฅธ hashCode ๋ฉ”์„œ๋“œ๋Š” ์–ด๋–ค ๋ชจ์Šต์ด์–ด์•ผ ํ• ๊นŒ?

 

1)

์ฝ”๋“œ11-1 ์ตœ์•…์˜ hashCode ๊ตฌํ˜„ - ์‚ฌ์šฉ ๊ธˆ์ง€!

@Override
public int hashCode() { return 42; }

๋ฌธ์ œ์ 

  • ๋ชจ๋“  ๊ฐ์ฒด์—์„œ ๋˜‘๊ฐ™์€ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ ํ•ด์‹œํ…Œ์ด๋ธ”์˜ ๋™์ผํ•œ ๋ฒ„ํ‚ท์— ๋‹ด๊ฒจ ๋งˆ์น˜ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์ฒ˜๋Ÿผ ๋™์ž‘ํ•จ
  • ํ‰๊ท  ์ˆ˜ํ–‰ ์‹œ๊ฐ„์ด O(1)์ธ ํ•ด์‹œํ…Œ์ด๋ธ”์ด O(n)์œผ๋กœ ๋А๋ ค์ง

 

2)

  • ์ข‹์€ ํ•ด์‹œ ํ•จ์ˆ˜๋ผ๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค์— ๋‹ค๋ฅธ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•จ
  • ์ด์ƒ์ ์ธ ํ•ด์‹œ ํ•จ์ˆ˜๋Š” ์ฃผ์–ด์ง„ ์„œ๋กœ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค๋“ค์„ 32๋น„ํŠธ ์ •์ˆ˜ ๋ฒ”์œ„์— ๊ท ์ผํ•˜๊ฒŒ ๋ถ„๋ฐฐํ•ด์•ผ ํ•จ
  • ์ด์ƒ์„ ์™„๋ฒฝํžˆ ์‹คํ˜„ํ•˜๊ธฐ๋Š” ์–ด๋ ต์ง€๋งŒ ๋น„์Šทํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฐ„๋‹จํ•œ ์š”๋ น์„ ๋‹ค์Œ๊ณผ ๊ฐ™์Œ

 

ํ•ด๋‹น ์š”๋ น์„ ์ ์šฉํ•œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Œ

์ฝ”๋“œ 11-2 ์ „ํ˜•์ ์ธ hashCode ๋ฉ”์„œ๋“œ

@Override
public int hashCode() {
    int result = Short.hashCode(areaCode);
    result = 31 * result + Short.hashCode(prefix);
    result = 31 * result + Short.hashCode(lineNum);
    return result;
}

 

์ถ”๊ฐ€

  • ํ•ด์‹œ ์ถฉ๋Œ์ด ๋” ์ ์€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๊ตฌ์•„๋ฐ”์˜ com.google.common.hash.Hashing ์ฐธ๊ณ 

 

3)

  • Objects ํด๋ž˜์Šค๋Š” ์ž„์˜์˜ ๊ฐœ์ˆ˜๋งŒํผ ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ณ„์‚ฐํ•ด์ฃผ๋Š” ์ •์  ๋ฉ”์„œ๋“œ์ธ hash๋ฅผ ์ œ๊ณตํ•จ
  • ํ•˜์ง€๋งŒ hash๋Š” ์†๋„๊ฐ€ 2) ๋ณด๋‹ค ๋” ๋А๋ฆผ
    • ์ž…๋ ฅ ์ธ์ˆ˜๋ฅผ ๋‹ด๊ธฐ ์œ„ํ•œ ๋ฐฐ์—ด์ด ๋งŒ๋“ค์–ด์ง€๊ณ , ์ž…๋ ฅ ์ค‘ ๊ธฐ๋ณธ ํƒ€์ž…์ด ์žˆ๋‹ค๋ฉด ๋ฐ•์‹ฑ๊ณผ ์–ธ๋ฐ•์‹ฑ์„ ๊ฑฐ์ณ์•ผ ํ•จ
    • ๋”ฐ๋ผ์„œ hash ๋ฉ”์„œ๋“œ๋Š” ์„ฑ๋Šฅ์— ๋ฏผ๊ฐํ•˜์ง€ ์•Š์€ ์ƒํ™ฉ์—์„œ๋งŒ ์‚ฌ์šฉํ•˜์ž

 

์ฝ”๋“œ 11-3 ํ•œ ์ค„์งœ๋ฆฌ hashCode ๋ฉ”์„œ๋“œ - ์„ฑ๋Šฅ์ด ์‚ด์ง ์•„์‰ฌ์›€

@Override
public int hashCode() {
    return Objects.hash(lineNum, prefix, areaCode);
}

 

4)

  • ํด๋ž˜์Šค๊ฐ€ ๋ถˆ๋ณ€์ด๊ณ  ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋น„์šฉ์ด ํฌ๋‹ค๋ฉด, ๋งค๋ฒˆ ์ƒˆ๋กœ ๊ณ„์‚ฐํ•˜๊ธฐ๋ณด๋‹ค๋Š” ์บ์‹ฑํ•˜๋Š” ๋ฐฉ์‹์„ ๊ณ ๋ คํ•ด์•ผ ํ•จ
  • ๊ฒฝ์šฐ์— ๋”ฐ๋ฅธ ๋ฐฉ์‹
    • ํ•ด๋‹น ํƒ€์ž…์˜ ๊ฐ์ฒด๊ฐ€ ์ฃผ๋กœ ํ•ด์‹œ์˜ ํ‚ค๋กœ ์‚ฌ์šฉ๋œ๋‹ค๋ฉด? --> ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŒ๋“ค์–ด์งˆ ๋•Œ ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ๊ณ„์‚ฐํ•ด๋‘ฌ์•ผ ํ•จ
    • ํ•ด์‹œ์˜ ํ‚ค๋กœ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด? --> hashCode๊ฐ€ ์ฒ˜์Œ ๋ถˆ๋ฆด ๋•Œ ๊ณ„์‚ฐํ•˜๋Š” ์ง€์—ฐ ์ดˆ๊ธฐํ™” ์ „๋žต ๊ณ ๋ คํ•ด์•ผ ํ•จ
      • ํ•„๋“œ๋ฅผ ์ง€์—ฐ ์ดˆ๊ธฐํ™”ํ•˜๋ ค๋ฉด ๊ทธ ํด๋ž˜์Šค๋ฅผ thread-safeํ•˜๊ฒŒ ๋งŒ๋“ค๋„๋ก ์‹ ๊ฒฝ์จ์•ผ ํ•จ (์•„์ดํ…œ 83)

 

์ฝ”๋“œ 11-4 ํ•ด์‹œ์ฝ”๋“œ๋ฅผ ์ง€์—ฐ ์ดˆ๊ธฐํ™”ํ•˜๋Š” hashCode ๋ฉ”์„œ๋“œ - ์Šค๋ ˆ๋“œ ์•ˆ์ •์„ฑ๊นŒ์ง€ ๊ณ ๋ คํ•ด์•ผ ํ•จ

private int hashCode; //์ž๋™์œผ๋กœ 0์œผ๋กœ ์ดˆ๊ธฐํ™”๋จ

@Override
public int hashCode() {
    int result = hashCode;
    if (result == 0) {
    	result = Short.hashCode(areaCode);
        result = 31 * result + Short.hashCode(prefix);
        result = 31 * result + Short.hashCode(lineNum);
        hashCode = result;
    }
    return result;
}

 

์ฃผ์˜

1) ์„ฑ๋Šฅ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ํ•ด์‹œ์ฝ”๋“œ ๊ณ„์‚ฐํ•  ๋•Œ ํ•ต์‹ฌ ํ•„๋“œ๋ฅผ ์ƒ๋žตํ•˜๋ฉด ์•ˆ๋จ

  • ํ•ด์‹œ ํ’ˆ์งˆ์ด ๋‚˜๋น ์ ธ ํ•ด์‹œํ…Œ์ด๋ธ”์˜ ์„ฑ๋Šฅ์„ ์‹ฌ๊ฐํ•˜๊ฒŒ ๋–จ์–ด๋œจ๋ฆด ์ˆ˜ ์žˆ์Œ

2) hashCode๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์˜ ์ƒ์„ฑ ๊ทœ์น™์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ž์„ธํžˆ ๊ณตํ‘œํ•˜์ง€ ๋ง์ž

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ด ๊ฐ’์— ์˜์ง€ํ•˜์ง€ ์•Š๊ฒŒ ๋˜๊ณ , ์ถ”ํ›„์— ๊ณ„์‚ฐ ๋ฐฉ์‹์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Œ

 

๐Ÿ“ํ•ต์‹ฌ ์ •๋ฆฌ

  • equals๋ฅผ ์žฌ์ •์˜ํ•  ๋•Œ๋Š” hashCode๋„ ๋ฐ˜๋“œ์‹œ ์žฌ์ •์˜ํ•ด์•ผ ํ•จ
  • ์žฌ์ •์˜ํ•œ hashCode๋Š” Object์˜ API ๋ฌธ์„œ์— ๊ธฐ์ˆ ๋œ ์ผ๋ฐ˜ ๊ทœ์•ฝ์„ ๋”ฐ๋ผ์•ผ ํ•˜๋ฉฐ, ์„œ๋กœ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค๋ผ๋ฉด ๋˜๋„๋ก ํ•ด์‹œ์ฝ”๋“œ๋„ ์„œ๋กœ ๋‹ค๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผ ํ•จ
  • AutoValue ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ IDE๋“ค์—์„œ equals์™€ hashCode๋ฅผ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•จ