📖본 포스팅은 'Effective java - 조슈아' 님의 책를 보고 작성되었습니다.
[equals를 재정의하지 않아야 하는 상황]
- 값을 표현하는 것이 아닌 동작하는 개체를 표현하는 클래스의 경우
- 각 인스턴스는 본질적으로 고유하다.
- Thread가 좋은 예시로 Object의 equals 메서드는 이러한 클래스에 딱 맞게 구현되어 있다.
- 논리적 동치성(logical equals)을 검사할 일이 없다.
- 논리적 동치성이란? 객체가 같은지를 확인하는 것이 아니라 객체가 가지고 있는 각 값이 같은지를 확인하는 것을 의미한다.
- 상위 클래스에서 재정의(Overriding)한 equals가 하위 클래스에 딱 들어 맞는 경우를 의미한다.
- 클래스가 private이거나 package-private이고 equals 메서드를 호출할 일이 없는 경우
[equals를 재정의해야 하는 상황]
- 객체 식별성(Object identity)이 아니라 논리적 동치성을 확인해야 하는데, 상위 클래스의 equals가 논리적 동치성을 비교하도록 재정의되지 않았을 경우에 equals를 재정의 해야 한다.
- 객체 식별성이란? 두 객체가 물리적으로 같은지를 나타내는 것이다.
- 주로 값 클래스가 equals를 재정의해야 하는 상황이 많다.
- 객체가 같은지 여부가 아닌 값이 같은지 여부를 알고 싶을 때다.
- 이를 재정의하면 Map의 키와 Set의 원소로 사용할 수 있게 된다.
- 그러나 값 클래스라 해도, 값이 같은 인스턴스가 둘 이상 만들어지지 않음을 보장하는 인스턴스 통제 클래스라면 equals를 재정의하지 않아도 된다.
[동치관계를 구현하며 다음을 만족하는 equals 메서드]
동치관계란?
집합을 서로 같은 원소들로 이루어진 부분집합으로 나누는 연산으로 이 부분을 동치류(equivalence class)라고 한다.
equals 메서드가 쓸모 있기 위해서는 모든 원소가 같은 동치류에 속한 어떤 원소와도 서로 교환할 수 있어야 한다.
이 동치 관계를 만족시키기 위한 다섯 요건은 아래와 같다.
[동치관계를 만족시키기 위한 다섯가지 요건]
- 반사성
- null이 아닌 모든 참조 값 x에 대해, x.equals(x)는 true이다.
- 쉽게 말해서 반사성은 객체는 자기 자신과 같이야 한다. 이 요건의 경우 일부러 어기는 경우가 아니라면 만족시키지 못하는 것이 더 어렵다.
- 대칭성
- null이 아닌 모든 참조 값 x,y에 대해, x.equals(y)가 true면 y.equals(x)도 true다.
- 두 객체는 서로에 대한 동치 여부에 똑같이 답해야 한다는 뜻이다.
- 추이성
- null이 아닌 모든 참조 값 x,,y,z에 대해 x.equals(y)가 true이고 y.equals(z)도 true면 x.equals(z)도 true다.
- 첫 번째 원소와 두 번째 원소가 같고 두 번째 원소와 세 번째 원소가 같다면 첫 번째 원소와 세 번째 원소도 같아야 한다는 뜻이다.
- 일관성
- null이 아닌 모든 참조 값 x,y에 대해 x.equals(y)를 반복해서 호출하면 항상 true를 반환하거나 항상 false를 반환한다.
- 두 객체가 같다면 영원히 같아야 한다는 뜻이다.
- null - 아님
- null이 아닌 모든 참조 값 x에 대해 x.equals(null)은 false다.
- 모든 객체가 null과 같지 않아야 한다는 뜻이다.
[equals 메서드 구현 방법]
- ==연산자를 사용해 입력이 자기 자신의 참조인지 확인한다.
- 자기 자신이면 true를 반환한다. 이는 단순 성능 최적화용으로 비교 작업이 복잡한 상황에 값어치를 할 것이다.
- float과 double을 제외한 기본 타입 필드는 == 연산자로 비교한다.
- 참조 타입 필드는 각각의 equals 메서드로 비교한다.
- float과 double 필드는 각각 정적 메서드인 Float.compare(float,float)와 Double.compare(double, double)로 비교한다.
- instanceof 연산자로 입력이 올바른 타입인지 확인한다.
- 올바른 타입이 아니라면 false를 반환할 것이다.
- 입력을 올바른 타입으로 형변환한다.
- instanceof 검사를 했기 때문에 이는 100% 성공한다.
- 입력 개체와 자기 자신의 대응되는 핵심 필드들이 모두 일치하는지 하나씩 검사한다.
- 모든 필드가 일치할 땐 true 하나라도 다르면 false를 반환한다.
[핵심 정리]
- 꼭 필요한 경우가 아니라면 equals를 재정의 하지 말자
- 많은 경우 Object의 equals가 우리가 원하는 비교를 수행해준다.
- 재정의해야 할 대는 그 클래스의 핵심 필드 모두를 빠짐없이 다섯가지 규약을 확실히 지켜가며 비교해야 한다.