Effective Java | #10. equals는 일반 규약을 지켜 재정의하라

보람·2022년 5월 9일
0

Effective-Java

목록 보기
11/25

equals 재정의하지 않는 것이 최선인 경우

  • 각 인스턴스가 본질적으로 고유할 때 : Thread처럼 동작하는 개체 표현시
  • 인스턴스의 '논리적 동치성(logical equality)'을 검사X : 두 패턴이 일치하는지 검사하지 말 것
  • 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는다.
    • 하위 클래스에서도 그대로 쓰는 것이 좋음
  • 클래스가 private이거나 package-private이고 equals 메서드를 호출할 일 X
  • Enum이나 인스턴스 통제 클래스처럼 인스턴스가 둘 이상 생성되지 않는다면(불변이라면) 필요X

그렇다면 언제 재정의하쥬?

  • 객체의 논리적 동치성을 확인해야 하는데, 상위 클래스의 equals가 이를 지원하지 않을때 재정의해야 함
  • 객체가 같은지가 아니라 두 객체의 값이 일치하느냐에 대해 알고 싶을 때

equals는 동치관계를 구현

아래 규약은 모두 null이 아닌 모든 참조값이라는 공통 규약이 있다.

반사성(reflexivity)

  • x.equals(x) - true (this같은 객체 본인은 본인과 동일하다는 뜻)

대칭성(symmetry)

  • x.equals(y) = true 이면, y.equals(x) = true

추이성(transitivity)

  • x.equals(y) = true, y.equals(z) = true 이면 x.equals(z) = true
  • 상위 클래스에는 없는 새로운 필드를 가지는 하위클래스 구현시 상위 클래스와 하위클래스 객체 비교를 할 때 추이성이 깨지기 쉬움
  • 구체 클래스를 확장해 새로운 값을 추가하면서 equals 규약을 만족시킬 방법은 존재하지 않음
  • 리스코프 치환 원칙에서는 어떤 타입에 있어 중요한 속성이라면 그 하위 타입에서도 마찬가지로 중요하므로 그 타입의 모든 메서드가 하위 타입에서도 똑같이 잘 작동해야 한다고 말한다.
  • 구체 클래스의 하위 클래스에서 값을 추가할 괜찮은 우회 방법은 상속 대신 컴포지션을 사용하라(item-18)이다.

일관성(consistency)

  • x.equals(y) 가 호출시 항상 true or false 하나의 값만을 반환
  • 두 객체가 같다면 영원히 같아야 한다.
  • equals 판단에 신뢰할 수 없는 자원이 끼어들게 해서는 안됨 ex) URL equals에 매핑되는 호스트 IP 주소 검사까지? 잉? IP주소는 계속 바뀔 수 있음 , url만 검사하는 것이 좋음

null-아님

  • x.equals(null) = false가 나와야 함
  • instanceof를 사용하면 null검사 코드 추가할 필요 없음

단계별 equals 메서드 구현 방법

  1. == 연산자를 사용해 입력이 자기 자신의 참조인지 확인
  2. instanceof 연산자로 입력이 올바른 타입인지 확인
  3. 입력을 올바른 타입으로 형변환한다.(2단계했으면 바로 통과)
  4. 입력 객체와 자기 자신의 대응되는 핵심 필드들이 모두 일치하는지 하나씩 검사
  • instanceof 에서 인터페이스를 사용했다면 필드값을 가져올 때도 인터페이스 메서드를 사용할 것

마지막 주의사항

  • 대칭적인가? 추이성이 있는가? 일관적인가?를 자문해보자.
  • equals를 재정의할 땐 hashCode도 반드시 재정의하자(item-11)
  • 너무 복잡하게 해결하지말자
  • public boolean equals(MyClass o){}이런식으로 Object 외의 타입을 매개변수로 받는 equals 선언 X (MyClass대신 반드시 Object 넣기)
  • equals를 재정의하고 테스트하는일이 힘들다면!! 작성하고자 하는 근본적인 코드를 제공해주는 AutoValue를 사용하자

핵심 정리

꼭 필요한 경우가 아니면 equals를 재정의하지 말자. 많은 경우에 Object의 equals가 여러분이 원하는 비교를 정확히 수행해준다. 재정의해야 할 때는 그 클래스의 핵심 필드 모두를 빠짐없이, 다섯 가지 규약을 확실히 지켜가며 비교해야 한다.

profile
백엔드 개발자

0개의 댓글