이 포스팅에서 작성하는 내용은 EFFECTIVE JAVA(이펙티브자바) 에서 발췌하였습니다.
아이템 10. equals는 일반 규약을 지켜 재정의하라
equals 메서드는 재정의하기 쉬워 보이지만 주의할 필요가 있다.
equals 메서드를 재정의하지 않는 다면 그 클래스의 인스턴스는 오직 자기 자신과만 같게 된다.
1. equals메서드를 재정의하지 않아도 되는 경우
1) 각 인스턴스가 본질적으로 고유한 경우 : 값을 표현하는 게 아니라 동작하는 개체를 표현하는 클래스가 해당. ex) Thread
2) 인스턴스의 '논리적 동치성'을 검사할 일이 없는 경우 : java.util.regex.Pattern은 equals를 재정의해서 두 Pattern의 인스턴스가 같은 정규표현식을 나타내는 지를 검사하는 방법도 있다. (논리적 동치성)
설계자가 이러한 논리적 동치성을 검사할 필요가 없다고 판단하는 경우 기본 equals를 사용할 수 있다.
3) 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞을 경우 : 대부분의 Set 구현체는 AbstractSet이 구현한 equals를 상속받아 사용, List 구현체들은 AbstractList로부터, Map 구현체들은 AbstractMap으로 부터 상속받아 사용
4) 클래스가 private이거나 package-private이고 equals 메서드를 호출할 일이 없는 경우 : 만약 equals 호출을 제한하고 싶은 경우 아래의 소스처럼 참고해도 좋다.
@Override
public boolean equals(Object o){
throw new AssertionError(); // 호출 금지
}
2. 재정의하지 않아도 되는 경우
두 객체의 논리적 동치성을 확인해야 하는데, 상위 클래스의 equals가 논리적 동치성을 비교하도록 재정의되지 않았을 때
주로 값 클래스(Integer, String 등)들이 여기에 해당한다. (이 값 클래스 객체를 equals로 비교하는 개발자는 객체의 주소가 아니라 값이 같은지를 알고 싶어하기 때문)
1) 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다.
첫 번째 객체와 두 번째 객체가 같고, 두 번째 객체와 세 번째 객체가 같다면, 첫 번째 객체와 세 번째 객체도 같아야 한다는 뜻. 참고로 상속받은 자식 클래스를 확장해 새로운 값을 추가하면서 equals 규약을 만족시킬 방법은 존재 X - 일관성 : null이 아닌 모든 참조 값 x,y에 대해 x.equals(y)를 반복해서 호출하면 항상 true or false를 반환한다.
두 객체가 같다면 앞으로도 영원히 같아야 한다는 뜻 - null-아님 : null이 아닌 모든 참조 값 x에 대해 x.equals(null)은 false다.
모든 객체가 null과 같지 않아야 한다는 뜻
@Override
public boolean euqals(Object o) {
// 묵시적 null 검사
if( !(o instanceof MyYpe))
return false;
...
}
2) 양질의 equals 메서드를 구현하는 방법
- == 연산자를 사용해 입력이 자기 자신의 참조인 지 확인(자기 자신이면 true를 반환)
이 단계가 필요한 이유 : 자기 자신의 참조인 지 확인함으로써 성능을 높이기 위해
float, double은 부동소수값과 같은 특수한 경우가 존재하기에 compare 메서드를 이용한다. - instanceof 연산자로 입력 파라미터가 올바른 타입인 지 확인
- 입력을 올바른 타입으로 형변환
- 입력 객체와 자기 자신의 대응되는 '핵심' 필드들이 모두 일치하는 지 하나 하나 확인
3) equals 메서드 재정의 시 주의사항
- equals를 재정의할 땐 hashcode도 반드시 재정의
- 너무 복잡하게 생각 X
- Object 외의 타입을 매개변수로 받는 equals 메서드는 선언하지 않는다.
(equals 메서드의 입력 파라미터 타입은 반드시 Object 여야 함) - equals 메서드를 재정의하고 테스트해주는 오픈소스 → AutoValue 프레임워크 (구글 제작)
직접 작성하는 것과 근본적으로 같은 코드를 생성해줌.
대다수의 IDE도 같은 기능을 제공하지만 AutoValue 만큼 깔끔하진 않음.
그렇지만 사람이 직접 작성하는 것 보단 IDE에 맡기는 편이 좋음(실수 방지)
3. 정리
꼭 필요할 때만 equals를 재정의하자.
equals를 재정의할 때는 그 클래스의 모든 핵심 필드를, 다섯 가지 규약을 확실히 지켜가며 비교하자.
AutoValue 프레임워크 사용도 고려하자
'BE > Java' 카테고리의 다른 글
[Effective Java] 아이템 12. toString을 항상 재정의하라. (0) | 2022.09.13 |
---|---|
[Effective Java] 아이템 11. equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2022.09.12 |
[Effective Java] 아이템 9. try-finally보다는 try-with-resources를 사용하라 (0) | 2022.09.07 |
[Effective Java] 아이템 8. finalizer와 cleaner 사용을 피하라 (0) | 2022.09.06 |
[Effective Java] 아이템 7. 다 쓴 객체 참조를 해제하라 (0) | 2022.09.05 |