[Java] equals와 hashCode는 왜 같이 재정의해야 할까?

킹발·2022년 9월 29일
0

Java

목록 보기
7/12
post-thumbnail

IDE Generate 기능에서 항상 equalshashCode를 같이 재정의해준다.

equals()의 반환값이 true 라면, hashCode() 의 반환값이 서로 같아야 한다는 규칙이 있다고 알고 있지만, 왜 그런 규칙이 존재하는지 예제를 통해서 알아보자.


equals만 재정의할 경우

예제 코드

예제를 위해서 Student클래스를 다음과 같이 정의하였고 equals() 메서드만 재정의 하였다.

class Student {
    private String name;
    private String gender;
    private int age;

    public Student(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name) && 
                Objects.equals(gender, student.gender);
    }
}

Student 객체 2개를 List에 담았기 때문에 출력결과는 당연히 2가 된다.

public static void main(String[] args) {
    ArrayList<Student> students = new ArrayList<>();

    students.add(new Student("홍길동", "남자", 26));
    students.add(new Student("홍길동", "남자", 26));

    System.out.println(students.size());
}
2

문제 발생

요구사항이 추가가 되었다. Collection에 중복되지 않는 Student 객체만 넣어라.

중복을 피하기 위해서 List가 아닌 Set으로 로직 변경을 해보자.

public static void main(String[] args) {
    HashSet<Student> students = new HashSet<>();

    students.add(new Student("홍길동", "남자", 26));
    students.add(new Student("홍길동", "남자", 26));

    System.out.println(students.size());
}
2

나의 의도와는 다르게 2 가 출력되었다.
hashCode() 를 같이 재정의하지 않았기 때문에 내 의도와 다르게 동작하고 있다.

결론

equals()hashCode() 를 같이 재정의하지 않는다면, hash 값을 사용하는 Collection 을 사용할 때 문제가 발생한다.

HashSet 이 의도와 다르게 동작한 이유

HashSet이 중복이라고 판단하는 기준

  • hashCode() 의 리턴 값이 일치하고,
  • equals() 의 리턴 값이 true 일 때

오류 해결

  • hashCode() 또한 재정의 해주면 의도대로 코드가 동작한다.
import java.util.HashSet;
import java.util.Objects;

class Student {
    private String name;
    private String gender;
    private int age;

    public Student(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name) &&
                Objects.equals(gender, student.gender);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, gender, age);
    }
}
public class EqualsAndHashCodeEx {
    public static void main(String[] args) {
        HashSet<Student> students = new HashSet<>();

        students.add(new Student("홍길동", "남자", 26));
        students.add(new Student("홍길동", "남자", 26));

        System.out.println(students.size());
    }
}
1

0개의 댓글