[Java] Equals와 HashCode

이상혁·2024년 7월 15일

Java

목록 보기
1/2

overview

참조형 타입을 비교하는 방법으로 ==와 Equals를 사용을 한다.
우리는 오늘 Equals에 대해서 알아볼 것이다.
그리고 Equals를 알게 되면 항상 같이 따라 나오는 HashCode가 있다.
이번 포스트에서는 Equals와 HashCode에 대해서 알아 볼 것이다.

Equals

우리는 두 가지 방법 중에 Eqauls에 대해서 알아보고자 한다.
Equals를 잘 설명을 하기 위해서 Student 클래스를 통해서 예시를 사용하겠다.

@RequiredArgsConstructor
public class Student {

    private final String name;

}

굉장히 단순한 객체를 만들었다.
Student라는 객체이고 name이라는 값을 갔는다.
이 Student 클래스로 객체 2개를 만들어서 equals를 재정의 하지 않았을 때와 재정의 했을 때를 비교를 해보자

equals를 재정의 하지 않았을 때

public class EqualsAndHashCode {

    public static void main(String[] args) {
**텍스트**
        Student studentA = new Student("student");
        Student studentB = new Student("student");

        boolean equals = studentA.equals(studentB);
        if (equals) {
            System.out.println("studentA와 student는 같다.");
            System.out.println("studentA : " + studentA);
            System.out.println("studentB : " + studentB);
        } else {
            System.out.println("studentA와 student는 다르다.");
            System.out.println("studentA : " + studentA);
            System.out.println("studentB : " + studentB);
        }

    }

}

EqualsAndHashCode라는 클래스의 main 메소드에 Student 클래스로 studentA와 studentB를 만들었다. 그리고 equals를 재정의를 하지 않은 상태에서 equals 메소드를 통해서 값을 비교해보자.
main 메소드를 실행을 해보았을 때, 결과를 보자.

studentA와 studentB가 다르다라는 것을 볼 수 있다.
같은 클래스, 같은 name으로 객체를 생성하였는데 왜 다를까?
그 이유는 equals를 재정의하지 않고 비교를 하게 되면 각 객체의 주소 값을 보고 비교를 한다.
즉, 두 객체는 다른 메모리 주소에 저장이 되기 때문에 다른 객체라고 판단을 한다.
두 객체를 같은 객체로 판단을 하기 위해서는 equals의 재정의가 필요하다.

equals를 재정의한 경우

이제, equals를 재정의한 경우를 보자.

@RequiredArgsConstructor
public class Student {

    private final String name;

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }

        Student student = (Student) obj;

        return Objects.equals(name, student.name);
    }
}

@Overrivde를 통해서 equals를 재정의를 해주었다.
그리고 나서 위에 main 메소드를 다시 시작을 해보자.

studentA와 studentB가 같다고 판단을 하고 있다.
이처럼 equals를 재정의를 통해서 논리적으로 같은 객체인지를 판단을 할 수 있다.

반대로 equals를 재정의하지 않으면 오직 자기 자신과만 같게 된다.

HashCode

Equals를 알게 되면 항상 따라오는 녀석이 있다.
바로 HashCode이다.

HashCode는 생성한 객체를 식별하는 고유한 코드이다.
HashCode 메소드는 이 HashCode를 재정의 하는 메소드이다.

그러면 이 HashCode를 재정의 하는 것은 왜 필요할까?

아래의 코드를 보자

package org.example.study.study.equalsAndHashCode;

import java.util.HashSet;
import java.util.Set;

public class EqualsAndHashCode {

    public static void main(String[] args) {

        Student studentA = new Student("student");
        Student studentB = new Student("student");

        boolean equals = studentA.equals(studentB);
        if (equals) {
            System.out.println("studentA와 student는 같다.");
            System.out.println("studentA : " + studentA);
            System.out.println("studentB : " + studentB);
        } else {
            System.out.println("studentA와 student는 다르다.");
            System.out.println("studentA : " + studentA);
            System.out.println("studentB : " + studentB);
        }

        Set<Student> studentSet = new HashSet<>();
        studentSet.add
studentA);
        studentSet.add(studentB);
        System.out.println("studentSetSize : " + studentSet.size());

    }

}

우리가 아까 보았던 EqualsAndHashCode에서 Student 클래스에 HashCode 메소드를 재정의하지 않은 상태에서 중복을 허용하지 않은 Collection의 Set을 사용해서 studentA와 studentB를 요소로 추가하고 그 크기를 출력하고 있다.

현재, studentA와 studentB는 논리적으로 같다고 판단을 하고 있다. 그래서 크기도 1이 될 것이라고 예상을 한다. main 메소드를 실행을 해보자.

결과를 보면 예상과 다르게 2가 나오는 것을 볼 수 있다.
그 이유는 뭘까?

studentSetSize : 2의 위를 보면 객체의 정보가 나오고 @ 뒤에 임의 값이 나오는 것을 볼 수 있다.
이 임의 값이 해쉬코드이다. Set이 두 객체를 다를 게 판단을 한 것은 이 해쉬 값이 다르기 때문이다.

Set의 경우 참조형 타입의 중복을 판단을 할 때는 먼저, HashCode의 값을 판단을 한다.
우리가 든 예시에 경우, 이 HashCode의 값이 다르기 때문에 다른 객체로 판단을 한 것이다.
만약, HashCode 값이 같으면 우리가 먼저, 재정의를 해주었던 Equals의 리턴 값으로 true이면 같은 객체, false이면 다른 객체라고 판단을 한다.

이 이유 때문에 Equals와 HashCode가 많이 묶여서 이야기가 나온다.
Set은 HashCode와 Equals 2가지를 보고 판단을 하기 때문이다.

그러면 HashCode를 재정의한 경우를 코드로 보자

@RequiredArgsConstructor
public class Student {

    private final String name;

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }

        Student student = (Student) obj;

        return Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

@로 hashcode 메소드를 재정의 하였고 이제 main 메소드를 실행해보자

결과를 보면 studentA와 studentB는 같고 정보 뒤에 HashCode도 같다.
그리고 studnetSetSize도 우리가 예상한 1이 나온다.

참고 자료

equals와 hashCode는 왜 같이 재정의해야 할까?
[Java] equals() & hashcode() 메서드는 언제 재정의해야 할까?

profile
꾸준히!

0개의 댓글