ITEM 11: Overriding hashCode
equals๋ฅผ ์ฌ์ ์ํ ํด๋์ค๋ hashCode๋ ์ฌ์ ์ํด์ผ ํ๋ค. ๋ง์ฝ hashCode๋ฅผ ์ฌ์ ์ํ์ง ์๋๋ค๋ฉด, ์ผ๋ฐ ๊ท์ฝ์ ์ด๊ธฐ๊ฒ ๋์ด HashSet์ด๋ HashMap๊ณผ ๊ฐ์ ์ปฌ๋ ์ ์ ์์๋ก ์ฌ์ฉ์ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์๋ค.
equals ๋น๊ต์ ์ฌ์ฉ๋๋ ์ ๋ณด๊ฐ ๋ณ๊ฒฝ๋์ง ์์๋ค๋ฉด, ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋๋ ๋์ ๊ทธ ๊ฐ์ฒด์ hashCode ๋ฉ์๋๋ ๋ช๋ฒ์ ํธ์ถํด๋ ์ผ๊ด๋๊ฒ ํญ์ ๊ฐ์ ๊ฐ์ ๋ฐํํด์ผํ๋ค.
equals(Object)
๊ฐ ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ค๊ณ ํ๋จํ๋ค๋ฉด, ๋ ๊ฐ์ฒด์ hashCode๋ ๋๊ฐ์ ๊ฐ์ ๋ฐํํด์ผํ๋ค.equals(Object)
๊ฐ ๋ ๊ฐ์ฒด๋ฅผ ๋ค๋ฅด๋ค๊ณ ํ๋จํ๋๋ผ๋, ๋ ๊ฐ์ฒด์ hashCode๊ฐ ์๋ก ๋ค๋ฅธ ๊ฐ์ ๋ฐํํ ํ์๋ ์์ผ๋ฉฐ, ํ์ง๋ง ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ํด์๋ ๋ค๋ฅธ ๊ฐ์ ๋ฐํํด์ผ ํด์ํ ์ด๋ธ์ ์ฑ๋ฅ์ด ์ข์์ง๋ค. ๋ง์ฝ ๋ชจ๋ ๊ฐ์ฒด์ hashCode๊ฐ ๋์ผํ ๊ฐ์ ๋ฐํํ๋ค๋ฉด, ํ๊ท ์ํ์๊ฐ์ด O(1)์์ O(n)์ผ๋ก ๋๋ ค์ ธ, ๊ฐ์ฒด๊ฐ ๋ง์์ง๋ฉด ์ธ ์ ์๊ฒ ๋๋ค.
๋ ผ๋ฆฌ์ ์ผ๋ก ๊ฐ์ ๊ฐ์ฒด๋ ๊ฐ์ ํด์ฌ์ฝ๋๋ฅผ ๋ฐํํด์ผํ๋ฉฐ, hashCode ์ฌ์ ์๋ฅผ ์๋ชปํ์ ๋ ๊ฐ์ฅ ํฌ๊ฒ ๋ฌธ์ ๊ฐ ๋๋ ๋ถ๋ถ์ด๋ค.
public final class PhoneNumber {
private final short areaCode, prefix, lineNum;
public PhoneNumber(short areaCode, short prefix, short lineNum){
this.areaCode = rangeCheck(areaCode, 999, "์ง์ญ์ฝ๋");
this.prefix = rangeCheck(prefix, 999,"ํ๋ฆฌํฝ์ค");
this.lineNum = rangeCheck(lineNum, 9999, "๊ฐ์
์๋ฒํธ");
}
private static short rangeCheck(int val, int max, String arg){
if(val < 0 || val > max){
throw new IllegalArgumentException(arg+" : "+val);
}
return (short) val;
}
@Override
public boolean equals(Object o){
if(o == this)
return true;
if(!(o instanceof PhoneNumber)){
return false;
}
PhoneNumber pn = (PhoneNumber) o;
return pn.lineNum == lineNum && pn.prefix == prefix && pn.areaCode == areaCode;
}
}
Map<PhoneNumber, String> map = new HashMap<>();
map.put(new PhoneNumber((short) 707,(short) 867,(short) 5309), "์ ๋");
System.out.println(map.get(new PhoneNumber((short) 707,(short) 867,(short) 5309))); // null
์ฌ๊ธฐ์ PhoneNumber
ํด๋์ค๋ hashCode๋ฅผ ์ฌ์ ์ํ์ง ์์, ๋
ผ๋ฆฌ์ ๋์น์ธ ๋ ๊ฐ์ฒด๊ฐ ์๋ก ๋ค๋ฅธ ํด์์ฝ๋๋ฅผ ๋ฐํํ์ฌ ๋ ๋ฒ์งธ ๊ท์ฝ์ ์งํค์ง ๋ชปํ๊ฒ๋๋ค.
@Override
public int hashCode(){
// int ๋ณ์ result ์ด๊ธฐํ ํ ํด๋น ํ๋์ ํด์์ฝ๋ ๊ณ์ฐ
// ๊ธฐ๋ณธํ์
ํ๋๋ผ๋ฉด Type.hashCode() ์ฌ๊ธฐ์๋ Short.hashCode();
int result = Short.hashCode(areaCode);
// ์์์ ๊ณ์ฐํ ํด์์ฝ๋๋ก result ๊ฐฑ์
// ์ฌ๊ธฐ์ 31์ ํ์์ด๋ฉด์ ์์์ด๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ
// ์ง์๋ 2๋ฅผ ๊ณฑํ๋ฉด ์ํํธ ์ฐ์ฐ๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์์์ผ ์ค๋ฒํ๋ก๊ฐ ๋ฐ์ํ๋ฉด ์ ๋ณด๋ฅผ ์๊ฒ ๋จ.
result = 31 * result + Short.hashCode(prefix);
result = 31 * result + Short.hashCode(lineNum);
// result ๋ฐํ
return result;
}
์์ hashCode๋ ์ข์ hashCode๋ฅผ ์์ฑํ๋ ๊ฐ์ฅ ๊ฐ๋จํ ์๋ น์ด๋ค. ์ฌ๊ธฐ์๋ ๊ธฐ๋ณธ ํ์
ํ๋์ด๊ธฐ ๋๋ฌธ์ Type.hashCode(f)
๋ฅผ ์ํํ์ง๋ง, ๋ง์ฝ ์ฐธ์กฐ ํ์
ํ๋์ด๋ฉด์, ์ด ํด๋์์ equals ๋ฉ์๋๊ฐ ํด๋นํ๋์ equals๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํด ๋น๊ตํ๋ค๋ฉด, ํด๋น ํ๋์ hashCode๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํ๋ฉด๋๋ค. ๋ง์ฝ ํ๋์ ๊ฐ์ด null์ธ ๊ฒฝ์ฐ 0์ ์ฌ์ฉํ๋ฉด ๋๋ค.
ํ๋๊ฐ ๋ฐฐ์ด์ด๋ผ๋ฉด, ํต์ฌ ์์ ๊ฐ๊ฐ์ ๋ณ๋์ ํ๋์ฒ๋ผ ๋ค๋ฃจ๊ณ , ๋ฐฐ์ด์ ํต์ฌ ์์๊ฐ ์๋ค๋ฉด ๋จ์ํ ์์(0)๋ฅผ ์ฌ์ฉํ๋ค. ๋ง์ฝ ๋ชจ๋ ์์๊ฐ ํต์ฌ ์์๋ผ๋ฉด Arrays.hashCode
๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
Map<PhoneNumber, String> map = new HashMap<>();
map.put(new PhoneNumber((short) 707,(short) 867,(short) 5309), "์ ๋");
System.out.println(map.get(new PhoneNumber((short) 707,(short) 867,(short) 5309))); // "์ ๋"
์์ ๊ฐ์ด hashCode๋ฅผ ์์ฑํ ํ ์คํธ ์ฝ๋๋ฅผ ์ํํ๋ฉด ๋์น์ธ ์ธ์คํด์ค์ ๋ํด ๋๊ฐ์ ํด์์ฝ๋๋ฅผ ๋ฐํํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค. ํ์ํ๋(๋ค๋ฅธ ํ๋๋ก๋ถํฐ ๊ณ์ฐํด ๋ผ ์ ์๋ ํ๋)๋ ๋ชจ๋ ๋ฌด์ํด๋ ๋๋ฉฐ, equals ๋น๊ต์ ์ฌ์ฉ๋์ง ์์ ํ๋๋ ๋ฐ๋์ ์ ์ธํด์ผ ํ๋ค.
๋ง์ฝ ํด์ ์ถฉ๋์ด ๋์ฑ ์ ์ ๋ฐฉ๋ฒ์ ๊ผญ ์จ์ผํ๋ค๋ฉด, ๊ตฌ์๋ฐ์ com.google.common.hash.Hashing
์ ์ฐธ๊ณ ํ๋ ๊ฒ์ด ์ข๋ค.
ํด๋์ค๊ฐ ๋ถ๋ณ์ด๊ณ ํด์์ฝ๋๋ฅผ ๊ณ์ฐํ๋ ๋น์ฉ์ด ํฌ๋ค๋ฉด, ๋งค๋ฒ ์๋ก ๊ณ์ฐํ๊ธฐ ๋ณด๋ค๋ ์บ์ฑํ๋ ๋ฐฉ์์ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ข๋ค.
private int hashCode;
@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;
}
ํด์์ ํค๋ก ์ฌ์ฉ๋์ง ์๋ ๊ฒฝ์ฐ๋ผ๋ฉด ๋ค์๊ณผ ๊ฐ์ด hashCode๊ฐ ์ฒ์ ํธ์ถ๋ ๋ ๊ณ์ฐํ๋ ์ง์ฐ ์ด๊ธฐํ ์ ๋ต๋ ์๋ค. ์ด๋ ์ค๋ ๋ ์์ ์ฑ๊น์ง ๊ณ ๋ คํด์ผํ๋ฉฐ, ์ฑ๋ฅ์ ๋์ด๊ณ ์ ํด์์ฝ๋ ๊ณ์ฐ์ ํต์ฌ ํ๋๋ฅผ ์๋ตํด์๋ ์๋๋ค.
hashCode๊ฐ ๋ฐํํ๋ ๊ฐ์ ์์ฑ ๊ท์น์ API ์ฌ์ฉ์์๊ฒ ์์ธํ ๊ณตํํ์ง ์์์ผ ํด๋ผ์ด์ธํธ๊ฐ ์ด ๊ฐ์ ์์งํ์ง ์๊ฒ๋๊ณ , ์ถํ์ ๊ณ์ฐ ๋ฐฉ์์ ๋ฐ๊ฟ ์ ์๋ค.
Last updated
Was this helpful?