본문은 Effective Java를 읽고 간단하게 정리한 글입니다. 필요에 따라 생략/수정된 부분이 있을 수 있으며, 내용이 추후 변경될 수 있습니다.
선결론
- 꼭 필요한 경우가 아니면 equals를 재정의하지 말자 -> 대부분의 경우에 Object.equals로 충분
- 재정의하는 경우엔 아래에서 서술할 규약을 잘 지켜서 할 것
equals를 재정의하지 않아야 할 때
- 각 인스턴스가 본질적으로 고유할 때 -> 객체 식별성(물리적 동치성)을 비교할 때
- 인스턴스의 논리적 동치성(logical equality)을 검사할 일이 없을 때
- 상위 클래스에서 재정의한 equals가 하위 클래스에도 유효할 때
- 클래스가 private이거나 package-private이고 equals메서드를 호출할 일이 없을 때
equals를 재정의해야 할 때
- 객체 식별성이 아닌 논리적 동치성을 확인해야 하지만, 상위 클래스의 equals가 이를 충족하지 않을 때 -> 값 클래스(Integer, String, ..)
- 하지만 값 클래스라 하더라도 값이 같은 인스턴스가 둘 이상 만들어지지 않음을 보장하는 인스턴스 통제 클래스라면 equals 재정의 X -> Enum
equals 메서드를 재정의할 때 따라야 하는 규약 5가지
- 반사성(reflexivity): null이 아닌 모든 참조 값 x에 대해, x.equals(x)는 true다
- 객체는 자기 자신과 같아야 한다
- 대칭성(symmetry): null이 아닌 모든 참조 값 x, y에 대해, x.equals(y)가 true면 y.equals(x)도 true다
- 두 객체는 서로에 대한 동치 여부에 똑같이 답해야 한다
- 추이성(transitivity): null이 아닌 모든 참조 값 x, y, z에 대해, x.equals(y)가 true이고 y.equals(z)도 true면 x.equals(z)도 true이다
- 첫 번째 객체와 두 번째 객체가 같고, 두 번째 객체와 세 번째 객체가 같다면, 첫 번째 객체와 세 번째 객체도 같아야 한다
- 일관성(consistency): null이 아닌 모든 참조 값 x,y에 대해, x.equals(y)를 반복해서 호출하면 항상 true를 반환하거나 항상 false를 반환한다.
- 별도의 수정이 이루어지지 않는다는 가정하에 두 객체가 같다면 앞으로도 영원히 같아야 한다
- null-아님: null이 아닌 모든 참조 값 x에 대해, x.equals(null)은 false다
- 모든 객체가 null과 같지 않아야 한다
양질의 equals 메서드 구현 방법
- == 연산자를 사용해 입력이 자기 자신의 참조인지 확인
- instanceof 연산자로 입력이 올바른 타입인지 확인
- 입력을 올바른 타입으로 형변환
- 입력 객체와 자기 자신의 대응되는 '핵심'필드들이 모두 일치하는지 하나씩 검사 -> 하나라도 다르면 false
- 대칭적인지? 추이성이 있는지? 일관적인지? 3가지를 자문할 것
이중 4번 항목에서 필드를 비교하는 방법에 대해 좀 더 살펴보자
- float와 double을 제외한 기본 타입 필드는 == 연산자로 비교한다
- 참조 타입 필드는 각각의 equals 메서드로 비교한다
- null도 정상 값으로 취급하는 참조 타입 필드의 경우, Objects.equals(Object, Object)로 비교해 NPE 발생을 예방
- 비교하기에 너무 복잡한 필드를 가진 클래스는 필드의 표준형(canonical form)을 저장해둔 후 표준형끼리 비교
- float와 double은 각각 Float.compare(float, float)와 Double.compare(double, double)로 비교한다
- 어떤 필드를 먼저 비교하느냐에 따라 equals의 성능을 좌우 -> cost를 고려하여 비교순서를 정할 것
마지막으로 다음 주의사항을 지키자
- equals를 재정의할 땐 hashCode도 반드시 재정의
- 너무 복잡하게 메서드 작성 X -> 필드의 동치성만 검사해도 위의 규약을 충분히 지킬 수 있음
- Object 외의 타입을 매개변수로 받는 equals 메서드는 선언하지 말 것(아래 예시)
@Override public boolean equals(MyClass o) { .. }
'책 > Effective Java' 카테고리의 다른 글
[이펙티브 자바] 아이템12: ToString을 항상 재정의하라 (0) | 2022.04.26 |
---|---|
[이펙티브 자바] 아이템11: equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2022.04.22 |
[이펙티브 자바] 아이템9: try-finally보다는 try-with-resources를 사용하라 (0) | 2022.04.20 |
[이펙티브 자바] 아이템7: 다 쓴 객체 참조를 해제하라 (0) | 2022.04.19 |
[이펙티브 자바] 아이템6: 불필요한 객체 생성을 피하라 (0) | 2022.04.18 |