반응형
아이템 10 : equals는 일반 규약을 지켜 재정의하라
equals 메서드는 재정의하기 쉬워 보이지만 곳곳에 함정이 도사리고 있어서 자칫하면 끔찍한 결과를 초래한다.
다음 상황 중 하나에 해당한다면 재정의하지 않는 것이 최선이다.
- 각 인스턴스가 본질적으로 고유하다
- 인스턴스의 '논리적 동치성'을 검사할 일이 없다.
- 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는다.
- 클래스가 private이거나 package-private이고 equals 메서드를 호출할 일이 없다.
그렇다면 equals를 재정의해야 할 때는 언제일까? 객체 식별성이 아니라 논리적 동치성을 확인해야 하는데, 상위 클래스의 equals가 논리적 동치성을 비교하도록 재정의되지 않았을 때다. 주로 값 클래스들이 여기 해당한다. 값 클래스란 Integer와 String처럼 값을 표현하는 클래스를 말한다.
equals 메서드를 재정의할 때는 반드시 일반 규약을 따라야 한다. 다음은 Object 명세에 적힌 규약이다.
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)가 ture고 y.equals(z)도 true면 x.equals(z)도 true다.
- 일관성 : null이 아닌 모든 참조 값 x, y에 대해, x.equals(y)를 반복해서 호출하면 항상 true를 반환하거나 항상 false를 반환한다.
- null-아님 : null이 아닌 모든 참조 값 x에 대해, x.equals(null)은 false다.
양질의 equals 메서드 구현 방법을 단계적으로 보자면 4가지로 볼 수 있다.
- == 연산자를 사용해 입력이 자기 자신의 참조인지 확인한다.
- instanceof 연산자로 입력이 올바른 타입인지 확인한다.
- 입력을 올바른 타입으로 형변환한다.
- 입력 객체와 자기 자신의 대응되는 '핵심' 필드들이 모두 일치하는지 하나씩 검사한다.
equals를 다 구현했다면 세 가지만 자문해보자. 대칭적인가? 추이성이 있는가? 일관적인가?
또한 알아두어야 할 주의사항이 있다.
- equals를 재정의할 땐 hashCode도 반드시 재정의하자
- 너무 복잡하게 해결하려 들지 말자.
- Object 외의 타입을 매개변수로 받는 equals 메서드는 선언하지 말자.
핵심 정리
꼭 필요한 경우가 아니면 equals를 재정의하지 말자. 많은 경우에 Object의 equals가 여러분이 원하는 비교를 정확히 수행해준다. 재정의해야 할 때는 그 클래스의 핵심 필드 모두를 빠짐없이, 다섯 가지 규약을 확실히 지켜가며 비교해야 한다.
반응형
'언어 > JAVA' 카테고리의 다른 글
[Effective Java] toString을 항상 재정의하라 (0) | 2020.03.14 |
---|---|
[Effective Java] equals를 재정의하거든 hashCode도 재정의하라 (0) | 2020.03.14 |
[Effective Java] try-finally보다는 try-with-resources를 사용하라 (0) | 2020.03.13 |
[Effective Java] finalizer와 cleaner 사용을 피하라 (0) | 2020.03.12 |
[Effective Java] 다 쓴 객체 참조를 해제하라 (0) | 2020.03.12 |