[1.6]equals vs hashcode()

Always·2025년 1월 6일
2

매일메일

목록 보기
12/69

https://www.maeil-mail.kr/question/70
요약: 두 객체가 논리적으로 동일하다는 의미는 해시코드가 같고, equals()메서드를 통해서 반환된 값이 true라는 의미이다.

equals

정의

일반적으로 equals 메서드는 두 객체가 동일한 객체인지를 판별 할 때 사용하는 메서드이다.

실행

@NoArgsConstructor
@AllArgsConstructor
public class Person {
    private int length;
    private int age;
}
	public static void main(String[] args) {
		Person person1 = new Person(190, 20);
		Person person2 = new Person(190, 20);

		log.info("person equals ? = {}", person1.equals(person2));

	}

이 때 실행결과는 같은 값이 나와야 할것 같지만 다른 값이 나온다. 왜냐하면 equals를 재정의 하지 않으면 Object.java에서 정의한 아래와 같은 메서드를 그대로 사용하기 때문이다.

    public boolean equals(Object obj) {
        return (this == obj);
    }

여기서 ==을 통해서 비교한 값은 두 객체의 주소값을 비교하는 것이다.

즉 위에서의 0x8427과 0x8326은 다르므로, object의 equals연산에서는 false가 나오는 것이 당연하다.

wrapper class는 아니던데?

		Long a1=1L;
		Long a2=1L;
		log.info("Long equals ? = {}", a1.equals(a2));

Long타입또한 Reference타입으로써 객체의 equals를 그대로 따르지만 위의 결과는 true가 나온다.
왜냐하면 Wrapper Class의 경우 자료형을 감싼 형태이므로, java에서 해당 equals를 아래와 같이 자료형의 비교를 정의 해주었기 때문이다.

public boolean equals(Object obj) {
       if (obj instanceof Long) {
           return value == ((Long)obj).longValue();
       }
       return false;
   }

적용

따라서 이러한 값에 대한 동등성을 보장하기 위해서는 overriding을 통해서 equals메서드를 아래와 같이 작성해야한다.

     @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Subscribe subscribe = (Subscribe) o;
            return Objects.equals(email, subscribe.email) && Objects.equals(category, subscribe.category);
        }

이를 통해서 equals연산시 객체의 값이 같으면 같은 객체로 취급할 수 있다.


Hash

하지만 우리가 값을 찾을 때의 시간을 줄이기 위해서 사용하는 hash연산의 경우 HashCode를 기반으로 table을 생성하기에 equals를 통한 객체의 동등성보장은 크게 의미가 없다.

적용

	public static void main(String[] args) {
		Person person1 = new Person(190, 20);
		Person person2 = new Person(190, 20);
		Set<Person> personSet=new HashSet<>(List.of(person1,person2));

		log.info("personSet size ? = {}",personSet.size());

		log.info("person equals ? = {}", person1.hashCode()==person2.hashCode());

	}

위에서 equals를 정의 했음에도 size는 2,아래의 값은 false가 나온다. 즉 아직 논리적으로 같은 객체가 아니라는 의미이다.
이 이유는 Hash기반의 컬랙션은 HashCode를 사용하여, 테이블을 만드는데, hashCode()메서드 역시 Object.java에서 제공하는 메서드로 사용되므로, 재정의가 필요하기 때문이다.

논리적으로 완벽하게 동등성을 유지,하기 위해서는 두개의 조건이 모두 충족되어야한다.

hashCode() overriding

@NoArgsConstructor
@AllArgsConstructor
public class Person {
    private int length;
    private int age;

    @Override
    public int hashCode() {
        return length*age;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(length, person.length) && Objects.equals(age, person.age);
    }

}

이 때는 1, true가 나오는데, 이는 HashSet에서 해당 객체가 논리적으로 동일한지를 판단할 때 hashcode판단-> equals판단을 통해서 둘다 true이면 동일하다고 판단하기 때문이다.

profile
🐶개발 블로그

0개의 댓글