์์์ ์ดํด๋ณธ ๊ฒ์ฒ๋ผ ์ข์ ํด์ ํจ์๋ผ๋ฉด ์๋ก ๋ค๋ฅธ ์ธ์คํด์ค์ ๋ค๋ฅธ ํด์ ์ฝ๋๋ฅผ ๋ฐํํ๋ค. ์ด์์ ์ธ ํด์ ํจ์๋ ์ฃผ์ด์ง (์๋ก ๋ค๋ฅธ) ์ธ์คํด์ค๋ค์ 32๋นํธ ์ ์ ๋ฒ์์ ๊ท ์ผํ๊ฒ ๋ถ๋ฐฐํด์ผ ํ๋ค. ์ด์์ ์๋ฒฝํ๊ฒ ์คํํ๊ธฐ๋ ์ด๋ ต์ง๋ง ๋น์ทํ๊ฒ ๋ง๋ค๊ธฐ๋ ๊ทธ๋ค์ง ์ด๋ ต์ง ์๋ค. ํด๋น ๊ธ์ ํตํด ํด์ ์ฝ๋๋ฅผ ๊ตฌํํ๋ 4๊ฐ์ง ๋ฐฉ๋ฒ๊ณผ ์ฃผ์ ์ฌํญ์ ์์๋ณด์.
1. ์ ํ์ ์ธ hashCode ๊ตฌํ ๐ฅ
- ํต์ฌ ํ๋ ์ค์ ํ๋๋ฅผ ๊ณจ๋ผ์ hashCode๋ฅผ ๊ตฌํ๋ค.
๊ธฐ๋ณธ ํ์ (primitive type) ํ๋๋ผ๋ฉด ํด๋น ํ์ ์ hashCode๋ผ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ๊ตฌํ๋ฉด ๋๋ค. (Type.hashCode(f))
์ฐธ์กฐ ํ์ (reference tyep) ํ๋๋ผ๋ฉด ํด๋น ํ์ ์ hashCode๋ฅผ ํธ์ถํด์ ๊ตฌํ๋ค. (Point๋ผ๋ ํ์ ์ ์ฌ์ฉํ๋ค๋ฉด point.hashCode()๋ฅผ ์ฌ์ฉํ๋ค.) - ์ด์ ์ ๊ฐ์ 31์ ๊ณฑํ๊ณ ๋ค์ ํ๋์ ํด์ ์ฝ๋ ๊ฐ์ ๋ํด์ค๋ค.
- 2๋ฒ์ ๋ฐฉ๋ฒ์ ๋ชจ๋ ํ๋์ ์ ์ฉํ๋ค.
public final class PhoneNumber {
private final short areaCode, prefix, lineNum;
public PhoneNumber(int areaCode, int prefix, int 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;
}
// ์ ํ์ ์ธ hashCode aptjem
@Override public int hashCode() {
int result = Short.hashCode(areaCode); // 1
result = 31 * result + Short.hashCode(prefix); // 2
result = 31 * result + Short.hashCode(lineNum); // 3
return result;
}
}
๊ณฑํ๋ ์ซ์๊ฐ 31์ธ ์ด์
- ํ์๋ฅผ ์จ์ผ ํจ
์ง์๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค์ 0์ด ์ฑ์์ง๋ฉด์ ์ซ์๊ฐ ๋ ์๊ฐ ์ ์๋ค. - ํด์ ์ถฉ๋ ๋ฐฉ์ง
31์ด๋ผ๋ ์ซ์๋ฅผ ์ฌ์ฉํ์ ๋ ํด์ ์ถฉ๋์ด ๊ฐ์ฅ ์ ์๋ค๊ณ ํ๋ค.
2. ์๋ ์์ฑ ๐ฅ
IntelliJ๊ฐ ์๋์ผ๋ก ๋ง๋ค์ด์ฃผ๋ hashCode()๋ฅผ ์ฌ์ฉํ๋ฉด ์๋์ ๊ฐ์ด ๊ตฌํํด ์ค๋ค.
@Override
public int hashCode() {
return Objects.hash(areaCode, prefix, lineNum);
}
3. ๊ตฌ์๋ฐ (Guava) ๐
ํด์ ์ถฉ๋์ด ๋์ฑ ์ ์ ๋ฐฉ๋ฒ์ ๊ผญ ์จ์ผ ํ๋ค๋ฉด ๊ตฌ์๋ฐ์ com.google.common.hash.Hashing์ ์ฐธ๊ณ ํ์.
@Override int hashCode() {
return Hashing.goodFastHash(32)
.hashObject(this, PhoneNumberFunnel.INSTANCE)
.hashCode();
}
private static class PhoneNumberFunnel implements Funnel<PhoneNumber> {
private static final PhoneNumberFunnel INSTANCE = new PhoneNumberFunnel();
@Override
public void funnel(PhoneNumber from, PrimitiveSink into) {
into.putShort(from.areaCode).putShort(from.prefix).putShort(from.lineNum);
}
}
4. ์บ์ฑํ๋ ๋ฐฉ์ ๐
ํด๋์ค๊ฐ ๋ถ๋ณ์ด๊ณ ํด์ ์ฝ๋๋ฅผ ๊ณ์ฐํ๋ ๋น์ฉ์ด ํฌ๋ค๋ฉด, ๋งค๋ฒ ์๋ก ๊ณ์ฐํ๊ธฐ๋ณด๋ค๋ ์บ์ฑํ๋ ๋ฐฉ์์ ๊ณ ๋ คํด์ผ ํ๋ค. ์ด ๋ฐฉ์์ ํด์ ์ฝ๋๋ฅผ ์ง์ฐ ์ด๊ธฐํ ํ๋ ๊ฒ์ด๋ค. ํ๋๋ฅผ ์ง์ฐ ์ด๊ธฐํํ๋ ค๋ฉด ๊ทธ ํด๋์ค๋ฅผ ์ค๋ ๋๊ฐ ์์ ํ๊ฒ ๋ง๋ค๋๋ก ์ ๊ฒฝ ์จ์ผ ํ๋ค.
private int hashCode; // ์๋์ผ๋ก 0์ผ๋ก ์ด๊ธฐํํ๋ค.
@Override public int hashCode() {
int result = hashCode;
if (result == 0) {
int result = Short.hashCode(areaCode);
result = 31 * result + Short.hashCode(prefix);
result = 31 * result + Short.hashCode(lineNum);
hashCode = result;
}
return result;
}
์ฃผ์ ์ฌํญ ๐ฉ
- ํต์ฌ ํ๋๋ฅผ ์๋ตํด์๋ ์ ๋๋ค.
์ฑ๋ฅ์ ๋์ธ๋ต์๊ณ ํด์์ฝ๋๋ฅผ ๊ณ์ฐํ ๋ ํต์ฌ ํ๋๋ฅผ ์๋ตํด์๋ ์ ๋๋ค. ์๋์ผ ๋นจ๋ผ์ง๊ฒ ์ง๋ง, ํด์ ํ์ง์ด ๋๋น ์ ธ ํด์ํ ์ด๋ธ์ ์ฑ๋ฅ์ ์ฌ๊ฐํ๊ฒ ๋จ์ด๋จ๋ฆด ์๋ ์๋ค. - ์ธ๋ถ์ ๋
ธ์ถํ ํ์๊ฐ ์๋ค.
hashCode๊ฐ ๋ฐํํ๋ ๊ฐ์ ์์ฑ ๊ท์น์ API ์ฌ์ฉ์์๊ฒ ์์ธํ ๊ณตํํ์ง ๋ง์. ๊ทธ๋์ผ ํด๋ผ์ด์ธํธ๊ฐ ์ด ๊ฐ์ ์์งํ์ง ์๊ฒ ๋๊ณ , ์ถํ์ ๊ณ์ฐ ๋ฐฉ์์ ๋ฐ๊ฟ ์๋ ์๋ค.
ํด๋น ๊ธ์ ๋ฐฑ๊ธฐ์ ๋์ '์ดํํฐ๋ธ ์๋ฐ ์๋ฒฝ ๊ณต๋ต'์ ์๊ฐํ๊ณ ์์ฑํ ๊ฒ์ ๋๋ค.