홈 › 중급 › 07 / 9

Object 메서드와 비교

equals, hashCode, toString, Comparable
섹션 7진행 0 / 9

4. 응용 변형 예제

변형 1: 여러 필드로 식별하는 equals

주문 상세는 (주문번호, 상품코드) 쌍이 식별자입니다.

java
@Override public boolean equals(Object o) {
    return o instanceof OrderLine other && orderNo == other.orderNo && Objects.equals(productCode, other.productCode);
}
@Override public int hashCode() { return Objects.hash(orderNo, productCode); }

Objects.equals 는 둘 다 null 이면 true, 하나만 null 이면 false 를 돌려주어 NPE 없이 참조 필드를 비교합니다. Objects.hash 는 가변 인자를 받아 조합 해시를 만듭니다. 필드가 두 개 이상이면 이 둘을 쓰는 것이 관례입니다.

변형 2: 정렬 기준을 상수로 이름 붙이기

java
public record Order(...) implements Comparable<Order> {
    public static final Comparator<Order> BY_AMOUNT_DESC = Comparator.comparing(Order::amount).reversed().thenComparing(Order::no);
    public static final Comparator<Order> BY_CUSTOMER = Comparator.comparing(Order::customer, Comparator.nullsLast(Comparator.naturalOrder()));
}
// orders.sort(Order.BY_AMOUNT_DESC);   화면의 정렬 옵션과 1:1 로 대응시킬 수 있다

화면에서 "정렬: 금액순/고객순" 을 고르면 Map<String, Comparator<Order>> 에서 꺼내 쓰는 구조가 됩니다.

변형 3: 금액을 식별에 쓰는 record 의 스케일 통일

java
public record Price(BigDecimal amount, String currency) {
    public Price { amount = amount.setScale(2, RoundingMode.HALF_UP); }   // 압축 생성자: 저장 전에 정규화 → equals 가 1.0 과 1.00 을 같게 본다
}

record 의 압축 생성자(매개변수 목록 없는 생성자)에서 값을 정규화하면 자동 equals 도 원하는 대로 동작합니다.

변형 4: 상속 관계에서의 equals

java
@Override public boolean equals(Object o) {
    if (o == null || getClass() != o.getClass()) return false;   // instanceof 대신 정확히 같은 클래스만
    ...
}

Member 를 상속한 VipMember 가 등급 필드를 추가하고 equals 를 다시 정의하면, member.equals(vip) 는 true 인데 vip.equals(member) 는 false 가 되어 대칭성이 깨집니다.

getClass() 비교는 이를 막지만 프록시 객체(JPA·Spring AOP)와는 다른 클래스로 판단되는 부작용이 있어, 프레임워크 엔티티는 instanceof 를 쓰고 하위 클래스에서 equals 를 다시 정의하지 않는 쪽이 일반적입니다.