equals 재정의가 필요하지 않은 경우
- 동치 관계인 인스턴스가 없다. (각 인스턴스가 본질적으로 고유하다)
- 생성한 인스턴스가 모두 다르다는 것 → 비교하는 것이 무의미하다.
- equals를 사용할 일이 없다.
- 인스턴스의 논리적 동치성(logical equality)를 검사할 일이 없다.
- equals 메서드를 사용할 경우가 없는 경우
- 클래스가
private
이거나package-private
인 경우
- 클래스가
- 쓸데없다.
- 상위 클래스에 구현된 equals를 그대로 사용하는 경우
equals 메서드 재정의 일반 규약
equals
메서드는 동치관계 (equivalence relation)를 구현하며, 다음 특성을 만족한다.
- 반사성(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다. - null이 아니다 :
null
이 아닌 모든 참조 값 x에 대해서x.equals(null)
은 false다.
예외 사항
구체 클래스를 확장할 때 새로운 필드 값 추가시 equals 규약 만족 불가하다.
따라서 이때는 상속 대신 컴포지션을 사용해야한다.
//속성1
public class Point {
int x;
int y;
@Override
public boolean equals(Object o) {
//규약에 맞게 구현
if (o == null) return false;
if (o == this) return true;
if(o instanceof Point){
Point p = (Point) o;
return p.x == this.x && p.y == this.y;
}
return false;
}
}
//속성 2
public class Color {
String colorName;
@Override
public boolean equals(Object o) {
//규약에 맞게 구현
if (o == null) return false;
if (o == this) return true;
if(o instanceof Color){
Color c = (Color) o;
return c.colorName.equals(this.colorName);
}
return false;
}
}
//컴포지션 방식
public class ColorPoint {
Point p;
Color c;
@Override
public boolean equals(Object o) {
//규약에 맞게 구현
if (o == null) return false;
if (o == this) return true;
if(o instanceof ColorPoint){
ColorPoint cp = (ColorPoint) o;
return cp.p.equals(this.p) && cp.c.equals(this.c);
}
return false;
}
}
//상속 방식
public class ColorPoint extends Point{
String colorName;
@Override
public boolean equals(Object o) {
//규약에 맞게 구현
if (o == null) return false;
if (o == this) return true;
if(o instanceof ColorPoint){
ColorPoint cp = (ColorPoint) o;
return super.equals(o) && cp.colorName.equals(this.colorName);
}
return false;
}
}
equals 구현 방법
==
연산자를 이용하여 입력이 자기 자신의 참조인지 확인해야 한다.- 자신의 참조라면 true를 반환해야 한다.
instanceof
연산자로 입력된 변수가 올바른 타입인지 확인해야 한다. 그렇지 않다면 false를 반환한다.- 입력을 올바른 타입으로 형변환한다. 위에서 타입을 검사했으므로 무조건 성공하게 됩니다.
- 입력된 객체와 자기 자신의 대응되는 핵심 필드들이 모두 일치한지 비교한다.
- 모든 필드가 일치하면 true, 그렇지 않다면 false를 반환한다.
- float와 double을 제외한 기본 타입(primitive type)은
==
연산자로 비교하고 - float와 double은 부동 소숫점 등을 위해
Float.compare
,Double.compare
로 비교한다. - 참조 타입 필드의 경우는 각각의 equals 메서드로 비교한다.
- 배열은
Arrays.equals
메서드를 사용한다.
핵심정리
꼭 필요한 경우가 아니면 equals
를 재정의하지 말자 Object
equals
가 많은 경우에 비교를 정확히 수행해준다. 재정의 해야 할때는 그 클래스의 핵심 필드를 모두 빠짐없이, 다섯가지 규약을 확실히 지켜가며 비교해야한다.
'programming > java' 카테고리의 다른 글
Item 12. toString을 항상 재정의하라. (0) | 2023.04.17 |
---|---|
Item 11. equals 재정의할 때 hashCode도 정의하라 (0) | 2023.03.29 |
Item 9. try-finally 보다는 try-with-resources를 사용하라 (0) | 2023.03.28 |
Item 8. finalizer와 cleaner의 사용을 피하라 (0) | 2023.03.24 |
Item7. 다 쓴 객체 참조를 해제하라 (0) | 2023.03.24 |