Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- 재정의
- cache
- lambda
- java
- DDL
- 생성자 주입
- StringBuilder
- 테스트 코드
- VUE
- MSA
- docker
- select_type
- Test
- 조합
- hashcode
- AOP
- 바이너리 카운팅
- 필드 주입
- stream
- DI
- equals
- Spring
- static
- jwt
- redis
- SQL
- 인덱스
- jpa
- KEVISS
- 열 속성
Archives
- Today
- Total
백엔드 개발자 블로그
[Effective Java] Item10. equals는 일반 규약을 지켜 재정의하라 본문
java의 Object들에 재정의를 하는 equals의 경우 잘못 사용하면 끔찍한 결과를 초래할 수 있습니다.
그래서 equals는 객체의 논리적 동치성을 확인해야할 때 빼고 불필요한 경우에는 재정의를 하지 않는 것이 더 좋습니다.
equals를 재정의하지 않아도 되는 상황
- 각 인스턴스가 본질적으로 고유한 경우
- 인스턴스의 논리적 동치성(logical equality)를 검사할 일이 없는 경우
- 상위 클래스에서 재정의한 equals가 하위 클래스에도 맞는 경우
- 클래스가 private, package-private이고 equals메서드를 호출할 일이 없는 경우
- equals를 호출될 일이 전혀 없는 경우 다음과 같이 막을 수도 있다.
@Override
public boolean equals(Object o) {
throw new AssertionError();
}
동치관계를 만족시키기 위한 다섯가지 요건
반사성(reflexivity)
- null이 아닌 모든 참조 값 x에 대해 x.equals(x)는 항상 true이다.
대칭성(symmetry)
- null이 아닌 모든 참조 값 x에 대해 x.equals(y) 와 y.equals(x) 같은 결과가 나와야 한다.
추이성(transitivity)
- null이 아닌 모든 참조 값 x, y, z에 대해, x.equals(y)가 true이고 y.equals(z)도 true이면 x.equals(z)도 true이다.
- 구체 클래스를 확장해 새로운 값을 추가하면서 equals 규약을 만족시킬 방법은 존재하지 않는다.
- 단, 추상 클래스의 하위 클래스에서는 equals규약을 지키면서도 값을 추가할 수 있다.
- 그 외에는 하위 클래스에서 값을 추가할 방법은 없지만, 상속대신 컴포지션을 사용하는 방법을 사용할 수 있다.
일관성(consistency)
- null이 아닌 모든 참조 값 x, y에 대해, x.equals(y)를 반복해서 호출하면 항상 true를 반환하거나 항상 false를 반환한다.
- 클래스가 불변이든 가변이든 equals의 판단에 신뢰할 수 없는 자원이 끼어들게 해서는 안 된다.
- equals는 항시 메모리에 존재하는 객체만을 사용한 결정적 계산만 수행해야한다.
null아님
- null이 아닌 모든 참조 값 x에 대해, x.equals(null)은 false이다.
- 해당 검사를 하기 위해 if(object == null) return false;와 같은 코드는 사용하지 말고 instanceof를 사용해 검사하자.
Override
public boolean equals(Object o) {
if (o instanceof MyType) return false;
MyType mt = (MyType) o;
...
}
좋은 equals메서드를 구현하는 순서
- ==연산자를 사용해 입력이 자기 자신의 참조인지 확인한다.
- instanceof로 입력이 올바른 타입인지 확인한다.
- 입력을 올바른 타입으로 형변환 한다.
- 입력 객체와 자기 자신의 대응되는 "핵심"필드들이 모두 일치하는지 하나씩 검사한다.
- 모든 필드가 일치하면 true, 하나라도 다르면 false반환
equals를 재정의 할 때 주의사항
- float, double을 제외한 기본 타입 필드는 ==를 통해 비교하고, 참조 타입은 equals메서드로 비교한다. float, double는 Float.compare(float, float); 와 Double.compare(double, double);로 비교한다. (부동 소수값을 다뤄야하기 때문)
- 때로는 null도 정상 값으로 취급하는 참조 타입 필드가 존재하여, 이러한 필드는 정적 메서드인 Object.equals(Object, Object);로 비교해 NullPointException을 발생시켜 예방방하는 것이 좋다.
- 비교하기 아주 복잡한 필드를 가진 클래스들으니 필드의 표준형을 저장해둔 후 표준형끼리 비교하면 경제적이다.
- 최상의 성능을 바란다면 다를 가능성이 크거나 비교하는 비용이 싼 필드를 먼저 비교하는 것이 좋다. (동기화용 lock 필드같이 객체의 논리적 상태와 관련 없는 필드는 비교하면 안된다.)
- equals를 다 구현하였으면 대칭적인지, 추이성은 있는지, 일관적인지 체크를 해봐야 한다.
- equals를 재정의 할 때 hashCode도 반드시 재정의해야 한다.
- 필드들의 동치성만 확인해도 equals 규약을 어렵지 않게 지킬 수 있음으로 너무 복잡하게 해결하려 들지 않는 것이 좋다.
- Object 이외의 타입을 매개변수로 받는 equals메서드는 재정의가 아니라 다중정의가 되는 것임으로 선언하지 말자!
핵심 정리
꼭 필요한 경우가 아니면 equals를 재정의하지 말자.
재정의해야 할 때는 다섯 가지 규약을 확실히 지켜가며 비교해야 한다.
'Java' 카테고리의 다른 글
[Effective Java] Item12. toString을 항상 재정의하라 (0) | 2024.04.04 |
---|---|
[Effective Java] Item11. equals를 재정의하려거든 hashCode도 재정의하라 (0) | 2024.04.02 |
[Effective Java] Item9. try-finally보다는 try-with-resources를 사용하라 (0) | 2024.03.30 |
[Effective Java] Item7. 다 쓴 객체 참조를 해체하라 (0) | 2024.03.22 |
[Effective Java] Item6. 불필요한 객체 생성을 피하라 (0) | 2024.03.22 |