@EqualsAndHashCode 그리고 HashCode와 Equals

jyleever·2023년 1월 8일
0

애노테이션

목록 보기
1/1

업무하면서 @EqualsAndHashCode 롬복을 자주 봤다. 스프링 프로젝트로 진행하면서 다양한 애노테이션을 사용하는 만큼 각 롬복이 무슨 역할을 하고 어느 상황에서 사용하는지 정확히 알아봐야 한다.

먼저 HashCode에 대해 간단하게 알아보자.

HashCode

  • 해싱 알고리즘에 의해 반환된 정수 값
    HashMap과 같은 자료 구조에서 사용되는 Hash Table에서의 hashing을 가능하게 하는 것을 목적으로 하고 있다.
  • equals 비교에 사용되는 정보가 변경되지 않았다면, 어플리케이션이 실행되는 동안 그 객체의 hashCode 메소드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 한다.(단, 애플리케이션을 다시 실행한다면 이 값이 달라져도 상관없다.)
  • equals(Object)가 두 객체를 같다고 판단했다면, hashCode는 똑같은 값을 반환해야 한다.
  • equals(Object)가 두 객체를 다르다고 판단했더라도, hashCode가 서로 다른 값을 반환할 필요는 없다. 단, 다른 객체에 대해서는 다른 값을 반환해야 해시테이블의 성능이 좋아진다.

그렇다면, HashCode는 어떤 원리로 구현되는 걸까? https://www.baeldung.com/java-hashcode#standard-hashcode-implementations 에 따르면 표준 구현 방식은 다음과 같다.

@Override
public int hashCode() {
    int hash = 7;
    hash = 31 * hash + (int) id;
    hash = 31 * hash + (name == null ? 0 : name.hashCode());
    hash = 31 * hash + (email == null ? 0 : email.hashCode());
    return hash;
}

물론, 매번 우리가 직접 HashCode를 오버라이딩하여 생성할 필요는 없다. 인텔리제이가 알아서 구현하는 기능도 제공하고, hash 메소드를 통해서도 생성할 수 있다.

위 HashCode 생성 방식에서 알 수 있는 사실은, HashCode는 객체의 주소값이 아니라, 내부 요소와 값을 다루며 그 값에 따라 HashCode 값도 바뀐다는 것이다.

Equals

String.equals는 가지고 있는 값이 동일하면 TRUE
String == 연산자는 주소값을 비교

  • 하지만, Object 클래스에서의 equalsequality is the same as object identity, 즉. 객체 동일성이다.

따라서 Object.equals() 메소드는 보통 하위 클래스에서 재정의를 통해 논리적으로 동등한지 비교할 때 주로 사용된다. https://www.baeldung.com/java-equals-method-operator-difference#2-equals-method-with-object-types

public class Person {
    // other fields and methods omitted
    @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 boolean equals (Object obj) {
	if (obj instanceof Member) {
		Member member = (Member) obj;
		if(id.equals(member.id)) {
			return true;
		}
	}
	return false;
}
  • non-null 객체를 참조할 때 사용하는 등가 관계 구현
    즉, 비교 대상이 되는 객체가 서로 같은 객체인지 판단

HashCode 와 Equals

  • HashCode : 두 객체가 같은 객체인지, 동일성(identity) 를 비교하는 연산자, 두 객체 내부 필드의 값들이 같은지 판단
  • Object.equals() : 두 객체의 내용이 같은지, 동등성(equality) 를 비교하는 연산자

@EqualsAndHashCode

Equality made easy: Generates hashCode and equals implementations from the fields of your object.
클래스 위에 정의하면, 컴파일 시점에 자동으로 객체의 필드로부터 HashCodeEquals를 오버라이딩하여 구현해주는 애노테이션
클래스에 있는 모든 필드들에 대한 비교를 수행함

  • 일반적으로 모든 non-static, non-transient 필드에서 사용할 수 있다

EqualsAndHashCode의 속성

@EqualsAndHashCode.Include, @EqualsAndHashCode.Exclude

특정 형식의 멤버에 위 속성을 사용하면서 Equals와 HashCode 생성을 위한 비교 수행에서 어떤 필드를 사용할지 수정할 수 있다.

기타 속성

  • onlyExplicitlyIncluded : equals와 hashCode 메소드 자동 생성 시, 정확히 @EqualsAndHashCode.Include가 붙은 메소드나 필드만 포함할지에 대한 설정
    • @EqualsAndHashCode(onlyExplicitlyIncluded = true)
  • CallSuper : equals와 hashCode 메소드 자동 생성 시 부모 클래스의 필드까지 감안할지 안 할지에 대해서 설정
    • callSuper = true : 부모 클래스 필드 값들도 동일한지 체크
      callSuper = false (기본값) : 자신 클래스의 필드 값들만 체크

참고

https://projectlombok.org/features/EqualsAndHashCode
https://www.baeldung.com/java-equals-method-operator-difference
https://www.baeldung.com/java-equals-hashcode-contracts
https://www.baeldung.com/java-hashcode
https://www.daleseo.com/lombok-popular-annotations/
https://junhyunny.github.io/information/java/equals-and-hashcode/
https://angelplayer.tistory.com/134
https://devlog-wjdrbs96.tistory.com/243

0개의 댓글