equals를 사용하지 않아도 되는 경우
1. 각 인스턴스가 본질적으로 고유할 때
equals의 목적은 값을 비교하는 것이다. Thread와 같이 동작을 목적이 되는 클래스는 재정의하지 않는다.
2. 논리적 동치성을 검사할 일이 없을 때
3. 상위 클래스에서 재정의한 equals가 하위 클래스에도 들어맞을 때
4. 클래스가 private이거나 package-private일 때
@Override
public boolean equals(Object obj) {
throw new AssertionError(); // 호출 금지
}
다음과 같이 에러를 뱉어내자!
그럼 equals는 언제 사용하는가
두 값 객체를 equals로 비교하는 개발자는 객체가 같은지가 아닌 값이 같은지를 비교하는 것이 목적이다.
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
위의 코드는 Integer 클래스에서 equals를 재정의 한 것이다.
value 값끼리 == 비교를 통해 주소 값이 같은지를 보고 있다. (값으로의 비교를 의미)
https://jwdeveloper.tistory.com/140
equals 메서드의 규약 (equals는 동치 관계를 구현한다.)
- reflexive - 반사성
null이 아닌 모든 참조 값 x에 대해, x.equals(x)는 ture
- symmetric - 대칭성
null이 아닌 모든 참조 값 x, y에 대해, x.equals(y)가 ture이면 y.equals(x) 도 true
- transitive - 추이성
null이 아닌 모든 참조 값 x, y, z에 대해 x.equals(y) y.equals(z)가 true이면 x.equals(z)도 true
- consistent - 일관성
null이 아닌 모든 참조 값 x, y에 대해서 x.equals(y) 무수히 반복하여도 결과는 항상 true 이거나 항상 false
- For any non-null reference value - null 아님
null이 아닌 모든 참조 값 x에 대해, x.equals(null)는 false
대칭성에 위배되는 경우
대소문자를 구분하지 않는 equals구현
public class CaseInsenstiveString {
private final String s;
public static void main(String[] args) {
CaseInsenstiveString cs = new CaseInsenstiveString("choi");
boolean result = cs.equals("cHoi");
System.out.println(result);
}
public CaseInsenstiveString(String s) {
Objects.requireNonNull(this.s = s);
}
public boolean equals(Object obj) {
if (obj instanceof CaseInsenstiveString) {
return s.equalsIgnoreCase(
((CaseInsenstiveString) obj).s);
}
if (obj instanceof String) {
return s.equalsIgnoreCase((String) obj);
}
return false;
}
}
결과는 당연히 true를 리턴한다.
하지만 String이 재정의한 equals를 사용한다면 어떻게 될까?
String s = "cHoi"; //String s = new String("cHoi");
boolean result2 = s.equals(cs);
결과는 false를 리턴한다.
이유는 String이 재정의한 equals는 CaseInsenstiveString의 존재를 모르기 때문이다. (String이 정의한 equals는 대소문자를 구별한다.)
컬렉션에 넣어서 비교
List<CaseInsenstiveString> list = new ArrayList<>();
list.add(cs);
boolean result3 = list.contains(s);
똑같이 결과는 false를 반환한다
String과 연동할 수 없음이 결론이 났음으로 아래와 같이 CaseInsenstivesTring 타입만을 비교하는 것으로 코드를 수정하자
public boolean equals(Object obj) {
return obj instanceof CaseInsenstiveString &&
((CaseInsenstiveString) obj).s.equalsIgnoreCase(s);
}
References
|
Code Link
https://github.com/mike6321/PURE_JAVA/tree/master/EffectiveStudy
'Java > Java' 카테고리의 다른 글
(JAVA) Exceptions in Java (1) (0) | 2020.02.03 |
---|---|
(JAVA) autoBoxing , unBoxing의 이해 (1) | 2020.02.03 |
(JAVA) equals에 대해서(1) (0) | 2020.01.31 |
(JAVA) Integer Cache (0) | 2020.01.29 |
(JAVA) wait() 와 notify() (0) | 2020.01.26 |