👉 공부하게 된 이유
- JPA를 사용하여 구현하다 보면 Entity에 관례처럼 사용하는 어노테이션 중 @EqualsAndHashCode와 @EqualsAndHashCode.Include의 정확한 역할을 알아보고 싶어서 공부를 하게 됨
👉 Entity 예제
@Getter
@Entity
@Table(name = "notification")
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor(access = PROTECTED)
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true)
public class Notification extends BaseEntity {
@Id
@EqualsAndHashCode.Include
@UuidGenerator(style = RANDOM)
@JdbcTypeCode(SqlTypes.VARCHAR)
@Column(name = "notification_id", columnDefinition = "VARCHAR(36)")
private UUID id;
@Column(name = "notification_type")
@Enumerated(EnumType.STRING)
private NotificationType notificationType;
@JdbcTypeCode(SqlTypes.VARCHAR)
@Column(name = "target_id", columnDefinition = "VARCHAR(36)")
private UUID targetId;
@Column(name = "is_read")
private boolean isRead;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "user_id")
private User user;
public void updateIsRead() {
this.isRead = true;
}
}
👉 @EqualsAndHashCode의 역할
- 클래스의 모든 필드를 기준으로
equals()와 hashCode() 메서드를 자동 생성하는 어노테이션
hashCode()는 객체를 식별하기 위한 정수 값을 반환하는 메서드
HashMap, HashSet, Hashtable 같은 해시 기반 컬렉션에서 객체를 빠르게 찾기 위해 사용
- 이 메서드는
equals()랑 같이 작동 해야 함 ⇒ 같다고 판단되는 객체(equals()가 ture인 경우)는 같은 hashCode를 가져야 하기 때문(자바 규칙)
- 만약 동일하지 않으면
user1과 user2의 equals() 결과는 true인데 hashCode가 달라서 HashSet에 둘 다 저장되는 경우가 생길 수 있음
equals(Object obj)는 두 객체가 논리적으로 같은지를 비교하는 데 사용
- 기본적으로
Object.equals()는 참조 주소를 비교
- 하지만 보통 원하는 건, ‘값이 같으면 같다’고 판단하는 것이기 때문에 Override 해서 사용
onlyExplicitlyIncluded = true
onlyExplicitlyIncluded = true를 사용하면 명시적으로 포함된 필드만을 기준으로 equals/hashCode를 생성
- ⇒ 이 때 사용하는 어노테이션이
@EqualsAndHashCode.Include
- id 필드에만
@EqualsAndHashCode.Include를 붙였기 때문에, equals()와 hashCode()는 오직 id만 기준으로 생성
callSuper = true
👉 왜 @EqualsAndHashCode를 사용해야 할까?
- JPA에서는 엔티티는 식별자(id)를 기준으로 동일성 비교를 해야 함
- 식별자가 같으면 같은 객체로 볼 수 있기 때문
- 모든 필드를 비교 대상으로 두거나
equals()랑 hashCode()를 Override를 하지 않으면 지연 로딩 프록시 객체 비교 이슈, 무한 루프 (양방향 관계) 등의 문제가 생길 수 있음