HashSet의 add메소드의 진실
HashSet의 add메소드는 새로운 요소를 추가하기 전에 기존 노드와 가튼 것인지 판별하기 위한 작업으로
추가하려는 노드의 eqauls()와 hashCode()를 호출하게 된다.
equals()와 hashCode()의 부재
import java.util.HashSet;
public class HashSetTest {
public static void main(String[] args) {
HashSet set = new HashSet();
set.add("123");
set.add("123");
set.add(new Person("KimJava", 100)); // ↓동일↓
set.add(new Person("KimJava", 100)); // ↑동일↑
System.out.println(set);
}
}
class Person{
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + ":" + age;
}
}
[abc, KimJava:100, KimJava:100]
위의 코드에서 Person 인스턴스를 new Person("KimJava", 100) 으로 2번 만들었다.
생각대로 라면 name(이름)과 age(나이)가 같으면 같은 사람으로 인식하도록 하였지만
Set에서 같은 사람으로 인식하지 않고 KimJava:100이 2번 출력되었다.
이 이유는 위에서 설명했듯이 add가 새로운 요소를 추가하기 전에 기존 노드와 가튼 것인지 판별하기 위한 작업으로
추가하려는 노드의 eqauls()와 hashCode()를 호출하게 되는데 이 두 메서드가 오버라이딩 되어 있지 않기 때문에
이런 결과가 나왔다.
equals()와 hashCode()의 오버라이드
import java.util.HashSet;
import java.util.Objects;
public class HashSetTest{
public static void main(String[] args) {
HashSet set = new HashSet();
set.add(new String("abc"));
set.add(new String("abc"));
set.add(new Person("KimJava", 100));
set.add(new Person("KimJava", 100));
System.out.println(set);
}
}
class Person {
String name;
int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
//equals를 오버라이딩 해주었다.
public boolean equals(Object obj) {
if(obj instanceof Person) {
Person tmp = (Person)obj;
return name.equals(tmp.name) && age==tmp.age;
}
return false;
}
//hashCode를 오버라이딩 해주었다.
public int hashCode() {
return Objects.hash(name, age);
}
public String toString() {
return name + ":" + age;
}
}
[abc, KimJava:100]
위와 같이 equals()와 hashCode()를 오버라이드 해주었더니 원하던 값이 출력됐다.
hashChde()를 오버라이딩 할때의 세가지 조건
1. 실행 중인 애플리케이션 내의 동일한 객체에 여러번 hashCode()를 호출해도 동일한 int값을 반환해야 한다. |
2. equals메서드를 이용한 비교에 의해서 true를 얻은 두 객체에 대해 각각 hashCode()를 호출해서 얻은 결과는 반드시 같아야 한다. |
3. equals메서드를 호출했을 때 false를 반환하는 두 객체는 hashCode() 호출에 대해 같은 int값을 반환하는 경우가 있어도 괜찮지만, 해싱(hashing)을 사용하는 컬렉션의 성능을 향상시키기 위해서는 다른 int값을 반환하는 것이 좋다 |
댓글