이펙티브 자바를 보면 equals
를 재정의하면 hashcode
도 재정의하라고 되어 있다. 왜 equals
만 재정의하면 안되는지 아래 코드를 보며 비교해보자
public class Test3 {
public static void main(String[] args) {
Person person1 = new Person(1, "A");
Person person2 = new Person(1, "A");
HashSet<Person> set = new HashSet<>();
set.add(person1);
set.add(person2);
for (Person person : set) {
System.out.println("person = " + person);
}
}
static class Person {
public int age;
public String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
}
위 코드는 equals
만 구현한 코드로 toString
은 결과값을 보기 편하게 하기 위해 재정의해주었다.
HashSet
을 선언하여 값이 같은 객체를 2개를 넣어주었다. Set
은 값이 같을 경우 하나만 넣어주는 자료구조 객체이므로 우리는 1개가 나올것으로 예상 할 수 있다.
😊그러면 실행해보자!
🤔!!???
값이 2개가 찍혔다. 찍힌 값을 보면 둘다 똑같이 age=1, name='A'로 동일하다 그런데도 Set
이 중복을 허용하고 있는 상황이다.
이유는 간단하다. HashSet
은 Hash
값을 기준으로 중복을 판단하는데 우리는 Hash
를 정의하지 않았기 때문이다.
한번 해시값을 찍어보면 알 수 있다.
System.out.println(person1.hashCode());
System.out.println(person2.hashCode());
hash
값이 다른 것을 확인 할 수 있다.
그러면 이번에는 hash
를 재정의해줘보자
@Override
public int hashCode() {
return Objects.hash(age, name);
}
😊이제는 값이 제대로 찍히는 것을 확인 할 수 있다.
equlas
만 재정의하면 위와 같이 hash
를 사용하는 자료구조에서 문제가 생길 수 있기에 equals
를 재정의한다면 hash
도 같이 재정의해줘야 한다.(document에서도 같이 재정의 해주라고 되어있다.)