아이템10. equals는 일반 규약을 지켜 재정의하라
ksy90101 opened this issue · comments
public boolean equals(MyClass o) {
...
}
'타입을 구체적으로 명시한' equals는 오히려 해가 된다. 이 메서드는 하위 클래스에서 @Override 애너테이션이 긍정 오류(거짓 양성)를 내게 하고 보안 측면에서도 잘못된 정보를 준다
.
이 두 가지 상황의 예시가 어떤 것이 있을까요? (이런 식으로 equals를 구현했던 적이 있었는데 잘못된 코드였네요😨)
-
하위 클래스에서 @OverRide 애너테이션이 긍정 오류(거짓 양성)을 내게 한다.
-> 하위 클래스에서는 주소값을 비교하고 싶지만 상위 클래스에서 일부 필드에 대해 논리적인 비교를 해두었을 때 긍정 오류가 발생할 수도 있는 오류? -
보안 측면에서도 잘못된 정보를 준다.
-> ?
- 위 equals는 책에서도 나오듯이
Object#equals
를 재정의한 것이 아니죠. 때문에 위MyClass#equals
가 true가 나오더라도 Java 프로그램/개발자가 흔히 아는Object#equals
가 아니다보니 긍정 오류라고 표현한 걸로 보여요 - 보안적인 측면은 아마 hashCode와 함께쓰이는 equals의 특성에 대한 내용같은데요. 이 참고 링크가 도움이 될거 같습니다.
1번 예시는 간단히 생각해봤는데요. (적절한 예시인지는 긴가민가하네요 ;;)
public interface LottoNumber {
}
public class UserLottoNumber implements LottoNumber {
private final int number;
public UserLottoNumber(int number) {
this.number = number;
}
public boolean isSame(LottoNumber lottoNumber) {
return this.equals(lottoNumber);
}
public boolean equals(UserLottoNumber userLottoNumber) {
if (this == userLottoNumber) return true;
if (userLottoNumber == null || getClass() != userLottoNumber.getClass()) return false;
UserLottoNumber that = userLottoNumber;
return number == that.number;
}
}
public class ResultLottoNumber implements LottoNumber {
private final int number;
public ResultLottoNumber(int number) {
this.number = number;
}
}
LottoNumber
는 따로 특별한 추상화를 하지않는 단순한 타입 홀더로 작동한다고 가정할께요.
여기서 유저가 발급받은 로또번호랑 결과로 나온 로또번호가 위와 같이 구현되어 있다고 볼께요.
이때 UserLottoNumber#equals
는 책에서처럼 인자가 타입을 구체적으로 드러내도록 구현했습니다.
단, UserLottoNumber#isSame
은 Object#equals
를 사용하고 있는데요. 때문에 같은 객체를 UserLottoNumber#equals
와 UserLottoNumber#isSame
에 같은 인자로 주어도 결과가 달라지는 상황이 나타나게 됩니다.
@Test
@DisplayName("equals 인자로 구체클래스 받는 경우")
void equals() {
// given
UserLottoNumber lottoNumber = new UserLottoNumber(1);
// when
boolean actual = lottoNumber.equals(new UserLottoNumber(1));
// then
assertThat(actual).isEqualTo(true);
}
@Test
void isSame() {
// given
UserLottoNumber lottoNumber = new UserLottoNumber(1);
// when
boolean actual = lottoNumber.isSame(new UserLottoNumber(1));
// then
assertThat(actual).isEqualTo(false);
}
경철님이 너무 잘 설명해주셨네요 ㅎㅎ
추가로 하위 클래스에서 @override 애너테이션이 긍정 오류(거짓 양성)을 내게 한다.
라는 말에 대해 제 의견을 적어보자면,
상위 클래스에서
public boolean equals(MyClass o) {
...
}
와 같이 equals를 잘못 정의하고 하위클래스에서 이를 @OverRide 한다면,
결국 잘못 정의한 equals를 오버라이드했는데도, 컴파일 에러는 안나겠죠?
이를 두고 긍정 오류(잘 될것이라고 예상했지만 잘 되지 못한 경우)라고 한 것 같습니다.