티스토리 뷰

CS/Java

자바의 equals()와 hashCode()

기억용블로그 2022. 8. 2. 12:17
728x90

자바에서 객체가 같은지 비교하기 위해 equals()와 hashCode()를 오버라이딩하여 사용한다.

동작 원리를 알아보고 왜 오버라이딩이 필요한지 알아보자.

 

오버라이딩 되지 않은 equals()

public boolean equals(Object obj) {
        return (this == obj);
}

 

오버라이딩하지 않은 Object의 equals()는 단순하게 객체의 주소값만을 비교해서 주소가 같으면 true 아니면 false를 반환한다.

==와 똑같이 동작한다.

 

String의 equals()

String의 equals는 다르게 동작한다. 자바에서 String은 항상 특별취급받는 존재이다!

 

String의 equals는 다음과 같다.

주소를 비교해서 같으면 true. charArray를 비교해가면서 다를 경우 false를 리턴하는 흐름으로 구현되어 있다.

 

String의 equals는 이미 오버라이딩이 되어있어 String간의 값비교 할 시 equals를 오버라이딩 할 필요없이 만들어져 있는 equals를 그냥 가져다 쓰면 되는 이유가 이것이다.

 

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String aString = (String)anObject;
        if (coder() == aString.coder()) {
            return isLatin1() ? StringLatin1.equals(value, aString.value)
                              : StringUTF16.equals(value, aString.value);
        }
    }
    return false;
}

 

String 이외의 다른 객체인 경우

String은 이미 내부적으로 equals가 값을 비교하도록 구현이 되어있지만 비즈니스 상에서 만들게 되는 객체들은 Object의 equals를 이용하게 된다. 즉 객체간 주소값을 비교하게 되는 것이다.

 

현실적으로 주소값만으로 객체의 동일성을 비교하는 경우는 드물기 때문에 equals를 오버라이딩하여 내가 원하는 기준으로 객체를 비교하고 동일성을 보장하는 것이다.

 

여기서 내가 원하는 기준이라는 내용이 중요한데, equals를 오버라이딩함에 있어 내부 비교용으로 어떤 것이 와도 상관이 없다는 얘기이다. 

즉 객체 내의 어떤 특정 필드 하나만을 기준으로 비교해서 그 값이 같으면 같은 객체라고 판정해도 되고 모든 값을 비교해서 같은 객체임을 판정해도 된다는 뜻이다.

 

equals() 오버라이딩의 한 예시

오버라이드하는 equals의 내용은 대충 보기에는 복잡해보이지만 대부분은 아래 코드와 같이 단순하게 값 비교 후 결과 리턴의 연속이다.

    @Override
    public boolean equals(final Object obj) {
    	//주소값이 같으면 true
        if (this == obj)
            return true;
        //값이 들어오지 않았다면 false
        if (obj == null)
            return false;
        //클래스가 다르다면 false
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        
        //중요하다고 생각하는 어떤 필드값을 기준으로.
        if (importantField == null) {
        	//한쪽에 필드가 존재하는데 다른 쪽에는 없을때 false
            if (other.importantField != null)
                return false;
          //필드값이 다르다면 false
        } else if (!importantField.equals(other.importantField))
            return false;
        //모든 조건을 통과하면 true
        return true;
    }

 

다시 한번 강조하지만 오버라이딩하는 equals는 내가 원하는 어떤 값을 어떤 식으로 비교해도 무관하다. 논리적으로 무결하다면!

 

오버라이딩 되지 않은 hashCode()

오버라이딩 되지 않은 hashCode는 해시 알고리즘에 의해 생성된 int값을 리턴한다.

hashCode의 특징은 해시 알고리즘에 의해 유일하다고 생각될 수 있는 값을 각 객체가 갖는 것이다.

그리고 해당값은 hash를 이용하는 HashMap, HashTable, HashSet 등에서 사용되는 값이다 (매우 중요)

@HotSpotIntrinsicCandidate
public native int hashCode();

 

어떤 두 객체가 같은 객체라고 판단하려면 equals에서 지정한 필드값들이 동일해야 하지만

그와 동시에 hashCode값도 동일해야한다. 

 

Hash를 이용하는 자료 구조는 hashCode()의 리턴값을 비교하고 true일시 equals 비교를 시행하여 이때도 true여야 같은 객체라고 판단하게 되는데

만약 equals만 오버라이딩한 이후에 Hash 자료구조에 추가하면 어떻게 될까?

 

모든 해시코드는 다를 것이라고 여겨지기 때문에 해시코드가 다르다면 다른 값이라고 판단하여 equals의 리턴값이 true라고 해도 hashCode() 비교로 이미 false가 나왔기에 서로 다른 객체라 판단하고 사실은 같은 객체를 해당 자료구조에 추가하게 된다.

 

 

결론

equals를 오버라이딩하게 된다면 hashCode도 반드시 오버라이딩해야 한다.

equals가 다르다면 hashCode는 같을 필요가 없다.

hashCode가 같더라도 equals는 다를 수 있다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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 29 30
글 보관함