equals 메서드는 Java의 Object 클래스에 정의된 메서드로, 두 객체가 "같음(equal)"을 결정하기 위해 사용된다. 모든 클래스에서 상속받으므로, 필요에 따라 오버라이드(재정의)하여 객체 간의 동등성 비교 방식을 커스텀할 수 있다.
기본 동작 :
public boolean equals(Object obj) {
return (this == obj);
}
기본적으로 Object 클래스의 equals 메서드는 두 객체의 참조가 같은지 확인한다. 즉, 두 참조가 메모리 상에서 같은 객체를 가리키는 경우에만 true를 반환한다.
equals를 재정의할 때 다음 중 하나라도 해당한다면 재정의하지 않는것이 좋다.
1. 각 인스턴스가 본질적으로 고유하다.
- 예를들어 Thread 클래스가 있다. Thread 클래스의 인스턴스는 각각 고유한 실행 스레드를 대표한다. 따라서, equals 메서드를 재정의하여 스레드 간의 '동등성'을 비교하는것은 의미가 없다.
2. 인스턴스의 논리적 동치성을 검사할 일이 없다.
- 해당 인스턴스가 대표하는 값이나 상태가 같은 다른 인스턴스와 "동등"하다고 판단할 필요가 없다는 의미이다. 즉, 객체의 동일성(identity)이 중요할 뿐, 두 개의 서로 다른 객체가 같은 값을 가진다는 개념이 의미가 없거나 관련이 없는 경우를 말합니다.
public class Session {
private final String sessionId;
public Session(String sessionId) {
this.sessionId = sessionId;
}
// 세션 ID에 기반한 동치성 비교가 의미가 없는 경우, equals 메서드를 재정의하지 않음
}
- 이처럼 세션ID가 같다고해서 두 세션의 인스턴스가 논리적으로 동등하다고 판단할 필요 자체가 없을경우 이다.
3. 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는다.
- 상위 클래스에서 재정의한 equals 메서드가 하위 클래스에서도 모든 면에서 적절하게 동작한다면, 하위 클래스에서 equals 메서드를 다시 재정의할 필요가 없다. 이 경우는 일반적으로 하위 클래스가 상위 클래스의 "동등성" 개념을 변경하지 않고, 추가적인 상태 정보 없이 상위 클래스의 동작을 확장할 때 발생한다.
4. 클래스가 private이거나 package-private이고 equals 메서드를 호출할 일이 없다.
- 클래스가 private이거나 package-private이고 그 인스턴스 간에 equals 메서드를 호출할 일이 없다면, 이는 해당 클래스가 매우 특정한 용도로 사용되며, 그 범위와 목적 내에서 인스턴스들의 동등성 비교가 로직적으로 의미가 없거나 필요하지 않다는 것을 의미할 경우 equals 메서드를 호출할 필요 자체가 없기때문에 재정의할 필요도 없는것이다.
이런 상황에 해당하지 않고 eqauls를 재정의 해야할 경우에는 반드시! 일반 규약을 따라야 한다.
1. 반사성(Reflexivity): 객체는 자기 자신과 동등해야 한다.
- 어떤 객체 x에 대해, x.equals(x)는 true를 반환해야 한다.
2. 대칭성(Symmetry): 두 객체의 동등성 검사는 방향에 무관해야 한다.
- 어떤 객체 x와 y에 대해, x.equals(y)가 true를 반환한다면, y.equals(x)도 true를 반환해야 한다.
3. 추이성(Transitivity): 첫 번째 객체가 두 번째 객체와 동등하고, 두 번째 객체가 세 번째 객체와 동등하면, 첫 번째 객체도 세 번째 객체와 동등해야 한다.
- 어떤 객체 x, y, z에 대해, x.equals(y)와 y.equals(z)가 true를 반환한다면, x.equals(z)도 true를 반환해야 한다.
4. 일관성(Consistency): 두 객체의 상태가 변하지 않는 한, equals 메서드의 호출 결과는 변경되지 않아야 한다.
- 어떤 객체 x와 y에 대해, 여러 번 x.equals(y)를 호출하더라도 항상 true를 반환하거나 항상 false를 반환해야 한다.
5. null에 대한 비동등성: 모든 객체는 null과 비교했을 때 false를 반환해야 한다.
- 어떤 객체 x에 대해, x.equals(null)은 false를 반환해야 한다.
어려워 보이지만 하나하나 읽어보면 당연한 말이다.
eqauls를 재정의를 해야만 하는 경우에는 5가지 일반규약을 따르고 검색해가며 단계별로 재정의를 하자. 하지만 일반 규약을 따르며 재정의해도 오류가 발생할 수 있다. equals 재정의를 했다면 대칭적인지, 추이성이 있는지, 일관적인지 단위 테스트를 작성해보는것이 좋다.
결론 : 정말 꼭 필요한 경우가 아니라면 equals를 재정의하지 말자. 대부분 equals가 개발자가 원하는 비교를 정확히 준다.
그냥 재정의 하지말자.
'이펙티브 자바' 카테고리의 다른 글
[이펙티브 자바] 아이템 12. toString을 항상 재정의하라 (0) | 2024.03.12 |
---|---|
[이펙티브 자바] 아이템 11. equals를 재정의하려거든 hashcode도 재정의하라 (0) | 2024.03.12 |
[이펙티브 자바] 아이템 9. try-finally보다는 try-with-resources를 사용하라 (0) | 2024.03.11 |
[이펙티브 자바] 아이템 8. finalizer와 cleaner 사용을 피하라 (0) | 2024.03.11 |
[이펙티브 자바] 아이템 7. 다 쓴 객체 참조를 해제하라 (0) | 2024.03.11 |