Java

[Java] equals() 와 hashcode

에드박 2021. 4. 12. 04:05

equals() 와 비교연산자 "=="

자바 모든 클래스의 최상위 클래스 Object 에 정의된 equals 메서드는 아래와 같습니다.

Object 의 equals() 메서드

 

객체끼리 비교연산자 "==" 로 비교한 결과를 반환해줍니다.

비교하는 두 객체의 참조값(객체가 저장된 주소값)이 같은지, 즉 두 객체가 동일한 객체인지 확인하는 메서드입니다.

 

자바에서 두 객체가 동등한지 비교할 때 흔히 equals 메서드를 사용합니다.

  • 논리적으로 동등하면 true 반환
  • 논리적으로 동등하지 않으면 false 반환

보통 값 객체의 경우 두 객체의 참조값이 아닌 상태를 가지고 비교를 하게 되는데

가장 대표적인 경우가 자바의 String 클래스 입니다.

String 클래스는 내부에 저장된 문자열 값 자체를 비교합니다.

따라서 String str1 = "aa" 와 String str2 = "aa 를 equals 메서드로 비교하면 같은 객체로 판단합니다.

 

기본형(Primitive Type) 은 "==" 을 통해 값 비교가 가능합니다.
하지만 사실 기본형도 값이 Runtime Constant Pool에 저장되어 있어 값이 같다면 같은 주소값을 가리키고 있을 뿐입니다.
기본형도 주소값으로 비교하지 않는것이 아닙니다.

즉, 기본형도 주소값으로 비교하지만 값이 같은 주소값을 가리키고 있을 뿐입니다.

 

 


 

객체의 동일성 비교와 동등성 비교

동일성 비교

  • 객체 인스턴스의 주소값을 비교하는것을 의미합니다.
  • 예를들어 Object 의 equals 메서드 또는 "==" 의 비교가 있습니다.

동등성 비교

  • 객체 내부의 값을 비교하는 것을 의미합니다.
  • 예를들어 String 의 equals() 메서드를 이용한 문자열 비교가 있습니다.

 

String 은 문자열 값을 매번 새로 생성하지않고 String pool 이라는것을 사용하기 때문에

아래 사진에서 str1 과 str2 는 같은 주소값을 참조하고 있습니다.

하지만 str3는 명시적으로 String 인스턴스를 생성하도록 하여 str1, str2 와는 다른 주소값을 가집니다.

실행결과

str1 == str2 는 두 객체가 같은 주소값을 참조하기 때문에 true를 반환합니다.

str1 == str3 는 두 객체가 다른 주소값이기 때문에 false를 반환합니다.

 

그렇다면 둘다 equals() 메서드를 사용해서 비교하면 어떤 결과가 나올까요?

실행결과

 

 

String 의 hashCode를 사용해서 비교해보면 값이 같으면 같다고 하는 동등성 비교를 하고있습니다.

 


hashCode() 메서드

객체의 해시코드란 객체를 식별하는 하나의 정수값을 의미합니다.

Object 의 hashCode 메서드

Object 의 hashCode 메서드는 객체의 메모리 주소를 이용해서 해시코드를 만들어 반환하기 때문에

객체마다 다른값을 가지고 있습니다.

 

객체의 동등성 비교시(객체의 값을 비교) hashCode를 오버라이딩할 필요가 있습니다.

이유는 컬렉션 프레임워크 HashTable, HashMap, HashSet 등에서 객체를 비교할 때

동등성 비교를 위해 equals() 와 hashCode() 메서드를 호출합니다.

 

우선 hashCode()를 먼저 호출하여 해시코드값이 같은지 판단하고 같다면 이후 equals() 메서드를 호출하여 한번 더 객체를 비교합니다.


HashTable에서 사용되는 hashCode() 와 equals() 메서드

(HashMap, HashSet 모두 동일합니다.)

 

HashTable은 <Key, Value> 형태로 저장됩니다.

이때 해시 함수(Hash Function)을 사용 즉, hashCode() 를 사용해서 key값을 기준으로 고유한 해시값을 생성한다.

이러한 해시값을 버킷(Bucket)에 저장합니다.

 

하지만 HashTable의 크기는 한정적이어서 서로 다른 객체라고 해도 같은 해시값을 갖게 될 수 있습니다.

 

서로 다른 객체인데 같은 해시값을 가지는 경우를 해시 충돌(Hash Collisions)라고 합니다.

이런 경우 버킷에 LinkedList의 형태로 객체를 추가합니다.

이처럼 같은 해시값의 버킷 안에 다른 값이 존재한다면 equals를 사용해서 비교를 합니다.

  • HashTable 에 put 하는경우
    • 값이 같은 객체가 이미 존재한다면 [equals() 가 true 라면] 기존 객체를 덮어쓴다.
    • 값이 같은 객체가 없다면 [equals() 가 false 라면] 해당 entry를 LinkedList에 추가한다.
  • HashTable 에 get 하는 경우
    • 값이 같은 객체가 있다면 [equals() 가 true인 경우가 있다면] 객체를 반환한다.
    • 값이 같은 객체가 없다면 [equals() 가 모든요소에 대해 false라면] null을 반환합니다.

 


객체의 정확한 동등성 비교를 위해서는 equals() 메서드만 재정의할게 아니라 hashCode도 재정의하여 논리적 동등 객체일 경우 동일한 해시코드가 반환되도록 해야합니다.