업무하면서 @EqualsAndHashCode 롬복을 자주 봤다. 스프링 프로젝트로 진행하면서 다양한 애노테이션을 사용하는 만큼 각 롬복이 무슨 역할을 하고 어느 상황에서 사용하는지 정확히 알아봐야 한다.
먼저 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 값도 바뀐다는 것이다.
String.equals
는 가지고 있는 값이 동일하면TRUE
String == 연산자
는 주소값을 비교
- 하지만, Object 클래스에서의
equals
는equality 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;
}
Equality made easy: Generates hashCode and equals implementations from the fields of your object.
클래스 위에 정의하면, 컴파일 시점에 자동으로 객체의 필드로부터HashCode
와Equals
를 오버라이딩하여 구현해주는 애노테이션
클래스에 있는 모든 필드들에 대한 비교를 수행함
@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