Java equals()์ hashCode()์ ๋ํด
equals()
- ๋ ๊ฐ์ฒด์
๋ด์ฉ์ด ๊ฐ์์ง
ํ์ธํ๋ Method์ ๋๋ค.
hashCode()
- ๋ ๊ฐ์ฒด๊ฐ
๊ฐ์ ๊ฐ์ฒด์ธ์ง
ํ์ธํ๋ Method์ ๋๋ค.
Example
Nesoy
๋ผ๋ ํด๋์ค๊ฐ ์กด์ฌํฉ๋๋ค.
class Nesoy {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Nesoy
๋ก ๋ง๋ค์ด์ง p1,p2๋ฅผ ๋์ผํ์ง ํ์ธํ์ง๋ง false ๊ฒฐ๊ณผ๊ฐ์ด ๋์์ต๋๋ค.
public static void main(String[] args){
Nesoy p1 = new Nesoy();
p1.setAge(27);
p1.setName("YoungJae");
Nesoy p2 = new Nesoy();
p2.setAge(27);
p2.setName("YoungJae");
System.out.println(p1.equals(p2)); // false
}
์(Why) ๊ฒฐ๊ณผ๊ฐ false์ผ๊น์?
- Object์ ์ ์๋ equals๋ฅผ ํ์ธํ๋ฉด ์ ๋ต์ ์ ์ ์์ต๋๋ค.
- ๋จ์ํ Object์ ==๋ก ๋น๊ตํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ป๊ฒ(How) ๊ฐ์ด ๋์ผํ์ง ๋น๊ตํ ์ ์์๊น์?
- equals()๋ฅผ @Overrideํ๋ฉด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this.getClass() != obj.getClass()) {
return false;
}
if (this == obj) {
System.out.println("Object Same");
return true;
}
Nesoy that = (Nesoy) obj;
if (this.name == null && that.name != null) {
return false;
}
if (this.age == that.age && this.name.equals(that.name)) {
System.out.println("Object Value Same");
return true;
}
return false;
}
Result
์ด๋ฐ ์ํฉ์ ์ด๋จ๊น์?
- equals()๊ฐ true์ธ ๋ Object๋ฅผ HashMap์ put์ ํ ๋ ๋์ผํ Key๋ก ์ธ์ํ๊ณ ์ถ์ ๊ฒฝ์ฐ
Map<Nesoy, Integer> map = new HashMap<Nesoy, Integer>();
map.put(p1, 1);
map.put(p2, 1);
System.out.println(map.size()); // 2
์(Why) ํฌ๊ธฐ๊ฐ 2์ผ๊น์?
- Hash๋ฅผ ์ฌ์ฉํ Collection(HashMap, HashTable, HashSet, LinkedHashSet๋ฑ๋ฑ)์ key๋ฅผ ๊ฒฐ์ ํ ๋ hashCode()๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๊ทธ๋ ์ต๋๋ค.
์ด๋ป๊ฒ(How) Key ๊ฐ์ด ๋์ผํ๊ฒ ์ธ์ํ ์ ์์๊น์?
- hashCode()๋ฅผ @Overrideํ๋ฉด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
@Override
public int hashCode() {
final int prime = 31;
int hashCode = 1;
hashCode = prime * hashCode + ((name == null) ? 0 : name.hashCode());
hashCode = prime * hashCode + age;
return hashCode;
}
Result
์ด๋ป๊ฒ(How) hashCode()๋ ๊ฒฐ์ ๋๋๊ฑธ๊น์?
Object์ hashCode()
- hashCode()๋ก native call์ ํ์ฌ Memory์์ ๊ฐ์ง ํด์ฌ ์ฃผ์๊ฐ์ ์ถ๋ ฅํฉ๋๋ค.
- ํน๋ณํ ์ค์ ์ ํ์ง ์์์ ๊ฒฝ์ฐ
System.identityHashCode()
์ ๋์ผํ ๊ฐ์ ๋ํ๋ ๋๋ค.
String์ hashCode()
์(Why) 31์ธ๊ฐ์?
31์ ์์์ด๋ฉด์ ํ์์ด๊ธฐ ๋๋ฌธ์ ์ ํ๋ ๊ฐ์ด๋ค. ๋ง์ผ ๊ทธ ๊ฐ์ด ์ง์์๊ณ ๊ณฑ์ ๊ฒฐ๊ณผ๊ฐ ์ค๋ฒํ๋ก๋์๋ค๋ฉด ์ ๋ณด๋ ์ฌ๋ผ์ก์ ๊ฒ์ด๋ค. 2๋ก ๊ณฑํ๋ ๊ฒ์ ๋นํธ๋ฅผ ์ผ์ชฝ์ผ๋ก shiftํ๋ ๊ฒ๊ณผ ๊ฐ๊ธฐ ๋๋ฌธ์ด๋ค. ์์๋ฅผ ์ฌ์ฉํ๋ ์ด์ ์ ๊ทธ๋ค์ง ๋ถ๋ช ํ์ง ์์ง๋ง ์ ํต์ ์ผ๋ก ๋๋ฆฌ ์ฌ์ฉ๋๋ค. 31์ ์ข์ ์ ์ ๊ณฑ์ ์ ์ํํธ์ ๋บ์ ์ ์กฐํฉ์ผ๋ก ๋ฐ๊พธ๋ฉด ๋ ์ข์ ์ฑ๋ฅ์ ๋ผ ์ ์๋ค๋ ๊ฒ์ด๋ค(31 * i๋ (i << 5) - i ์ ๊ฐ๋ค). ์ต์ VM์ ์ด๋ฐ ์ต์ ํ๋ฅผ ์๋์ผ๋ก ์คํํ๋ค.
- ์์์ด๋ฉด์ ํ์์ด๊ธฐ ๋๋ฌธ์ ์ ํ๋ ๊ฒ์
๋๋ค.
- ์์๋ 1๊ณผ ์๊ธฐ ์์ ์ ์ ์ธํ ์ซ์์ด๊ธฐ ๋๋ฌธ์ Hashํ์์ ๊ฒฝ์ฐ ์ถฉ๋์ด ๊ฐ์ฅ ์ ์ ์ซ์์ ๋๋ค.
- ์ธ์ ๋ ์ง ๋ณ๊ฒฝ๋ ๊ฐ๋ฅ์ฑ์ด ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ ๋ฆฌํ๋ฉฐ
- equals()๋ฅผ ์ฌ์ ์ํ๋ค๋ฉด side effect๋ฅผ ์ค์ด๊ธฐ ์ํด์ hashCode()๋ ์ฌ์ ์ํ๋๊ฒ์ด ์ข์ต๋๋ค.
Reference
- https://blog.weirdx.io/post/3113
- https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html
- https://stackoverflow.com/questions/299304/why-does-javas-hashcode-in-string-use-31-as-a-multiplier
- https://johngrib.github.io/wiki/Object-hashCode/#%EA%B7%B8%EB%9F%B0%EB%8D%B0-%EC%99%9C-31%EC%9D%84-%EA%B3%B1%ED%95%98%EB%8A%94-%EA%B1%B8%EA%B9%8C