1. 개념
equals를 단순히 재정의 하는 것은 쉽지만 함정이 많다. 이번 장에서는 equals를 재정의 할 때 고려해야 하는 점과, 재정의가 완료된 후 확인해야 하는 부분들에 대해 다루고 있다.
2. equals를 재정의하는 경우와 재정의하지 말아야 하는 경우
2-1. equals를 재정의하지 말아야 할 경우
- 각 인스턴스가 본질적으로 고유한 값을 표현하는 클래스: 예를 들어, Thread 클래스는 각 인스턴스가 고유한 ID를 가지므로 equals를 재정의할 필요가 없다.
- 논리적 동치성 검사가 필요 없는 경우: 대부분의 경우 객체 식별성만 중요하며, 논리적 동치성은 필요하지 않을 수 있다.
- 상위 클래스에서 재정의한 equals가 하위 클래스에 적절한 경우: 상위 클래스에서 이미 equals를 적절히 구현했고, 이를 하위 클래스에서 그대로 사용해도 무방한 경우이다.
- 접근이 제한된 클래스: equals를 호출할 일이 없는 private이나 package-private 클래스일 경우, 재정의할 필요가 없다.
2-2. equals를 재정의해야 할 경우
- 논리적 동치성 비교가 필요한 경우: 객체의 내용이 같은지를 비교해야 할 때, 상위 클래스의 equals가 이를 충족시키지 않을 때 재정의가 필요하다.
3. equals 메서드의 규약
Object 기본 명세의 equals 메서드는 다음의 규약을 준수해야 한다:
- 반사성 (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-아님 (Non-nullity): 모든 null이 아닌 참조 값 x에 대해, x.equals(null)은 항상 false여야 한다.
4. equals 구현 방법
- == 연산자를 사용하여 입력이 자기 자신의 참조인지 확인한다.
- instanceof 연산자로 입력이 올바른 타입인지 확인한다.
- 입력을 올바른 타입으로 형변환한다.
- 입력 객체와 자기 자신의 대응되는 핵심 필드들이 모두 일치하는지 하나씩 검사한다.
5. equals 구현 후 점검
새로 구현된 equals 메서드가 대치성, 추이성, 일관성을 유지하는지 확인해야한다.
6. equals를 재정의하는 예
경험했던 equals를 재정의하는 예로는 보통 값 객체(value object, VO)가 있다. 예를 들어 User 클래스에서 식별자 id가 같으면 같은 사용자로 간주할 수 있다. 이 경우, equals를 id 필드를 기준으로 재정의하여 사용자 객체의 논리적 동치성을 정확히 비교할 수 있다.
7. 정리
- 꼭 필요한 경우가 아니면 equals를 재정의하지 말아야 한다. Object의 기본 equals 메서드가 대개 원하는 비교를 수행해 준다.
- 꼭 필요한 경우라면 앞서 정리한 다섯 가지 규약을 반드시 지켜가며 equals를 구현해야 한다.
'이펙티브 자바' 카테고리의 다른 글
[이펙티브 자바] 9. try-finally 보다는 try-with-resources를 사용하라 (1) | 2024.04.06 |
---|---|
[이펙티브 자바] 8. finalizer 와 cleaner 사용을 피하라 (1) | 2024.03.31 |
[이펙티브 자바] 7. 다 쓴 객체 참조를 해제하라 (0) | 2024.03.27 |
[이펙티브 자바] 6. 불필요한 객체 생성을 피하라 (0) | 2024.03.26 |
[이펙티브 자바] 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2024.03.25 |