equals와 hashCode

전홍영·2022년 9월 20일
0

Java

목록 보기
7/15

모든 클래스는 Object 클래스를 상속받는다.

Object 클래스에는 hashCode 메소드와 equals 메소드를 가지고 있어 자식 클래스들은 이를 오버라이딩하여 작성한다.

equals() 와 hashCode()

  • equals는 두 객체의 내용이 같은지, 동등성을 비교하는 연산자
  • hashCode는 두 객체가 같은 객체인지, 동일성을 비교하는 연산자

그러나 equals를 재정의할 때는 지켜야할 규약이 있다.

  1. 반사성 : 객체는 자기 자신과 같아야 한다.
  2. 대칭성 : 두 객체는 서로에 대한 동치 여부에 똑같은 결과가 나와야 한다.
  3. 추이성 : 첫 번째 객체와 두 번째 객체가 같고 두 번째 객체와 세 번째 객체가 같으면 첫 번째 객체와 세 번째 객체가 같다.
  4. 일관성 : 두 객체가 같다면(어느 하나 혹은 두 객체 모두가 수정되지 않는 한) 앞으로도 영원히 같아야 한다.
  5. 모든 객체가 null과 같지 않아야 한다.

이 규약을 잘 지켜야 equals를 제대로 재정의할 수 있다.

왜 equals()와 hashCode()를 같이 재정의 해야 할까?

public class Car {
    private final String name;

    public Car(String name) {
        this.name = name;
    }

    // intellij Generate 기능 사용
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Car car = (Car) o;
        return Objects.equals(name, car.name);
    }
}
public static void main(String[] args){
  	List<Car> Listcars = new ArrayList<>();
    Listcars.add(new Car("foo"));
    Listcars.add(new Car("foo"));

    System.out.println(Listcars.size());//2가 나온다.
    
    Set<Car> Setcars = new HashSet<>();
    Setcars.add(new Car("foo"));
    Setcars.add(new Car("foo"));

    System.out.println(Setcars.size());//1이 아닌 2가 나온다.
}

왜 Setcars는 중복이 없어야할 Set의 사이즈가 1이 아닌 2가 나올까?

  • 문제는 HashSet에 있다. hash 값을 사용하는 Collection(HashSet, HashMap, HashTable)을 사용할 때 문제가 발생한다.
  • Collections에서 객체 같은지 비교할 때 첫 번째로 hashCode()의 리턴 값이 일치하고 equals()의 리턴값이 같아야 논리적으로 같은 객체라고 판단한다.
  • 위의 예에서도 Setcars에 객체가 추가될 때도 같은 과정을 통해 객체가 추가되었으나 hashCode()의 값이 같도록 Car클래스에 재정의 되지 않았기 때문에 다른 객체로 판단된 것이다.
  • Object 클래스에서는 hashCode()에 각 객체에 각기 다른 int 값을 리턴한다. 따라서 Car 클래스에서 hashCode를 재정의해야 한다.
  • Objects.hash() 메서드는 hashCode()를 재정의 하기 위해 사용할 수 있는 메서드이다. 이는 성능에 민감한 프로그램이 아닌 이상 사용해도 문제 없지만 직접 정의해주어야 할 수도 있다. hashCode() 재정의
public class Car {
    private final String name;

    public Car(String name) {
        this.name = name;
    }

    // intellij Generate 기능 사용
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Car car = (Car) o;
        return Objects.equals(name, car.name);
    }

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

Hash값을 사용하지 않는 Collection을 사용하지 않으면 hashCode()를 재정의할 필요 없지 않은가?

  • hash 값을 사용하는 Collection을 사용안할 자신이 있다면 사용하지 않아도 된다...그러나 미래는 알 수 없기에 재정의해 주는 것이 좋다.

참고
equals와 hashCode는 왜 같이 재정의해야 할까
Java 의 equlas 과 hashCode, 동등성과 동일성

profile
Don't watch the clock; do what it does. Keep going.

0개의 댓글