본문 바로가기

Java/Java

(JAVA) equals에 대해서(2)

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

 

(JAVA) Integer Cache

Integer 초기화 방식에 대해서 알아보자 Integer i = 123; 해당한 줄 이 어떻게 생성이 될까? @HotSpotIntrinsicCandidate public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCa..

jwdeveloper.tistory.com


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

 

https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/Object.html#equals(java.lang.Object)

 

Object (Java SE 13 & JDK 13 )

java.lang.Object public class Object Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class. Since: 1.0 See Also: Class Constructor Summary Constructors  C

docs.oracle.com


대칭성에 위배되는 경우

 

대소문자를 구분하지 않는 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

이펙티브 자바 Effective Java 3/E
국내도서
저자 : 조슈아 블로크(Joshua Bloch) / 이복연(개앞맵시)역
출판 : 인사이트 2018.11.01
상세보기

Code Link

https://github.com/mike6321/PURE_JAVA/tree/master/EffectiveStudy

 

mike6321/PURE_JAVA

Contribute to mike6321/PURE_JAVA development by creating an account on GitHub.

github.com

 

'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