ecsimsw

HashCode 와 System.identityHashCode 본문

HashCode 와 System.identityHashCode

JinHwan Kim 2020. 4. 11. 02:19

HashCode

 

hashCode 역시 equals와 마찬가지로 Object에 속하여 기본 구현은 객체의 주소를 기준으로 객체를 식별할 수 있는 정수 코드를 리턴하는 메소드이다. 

 

내용 값을 기준으로 식별 값을 리턴한다. 아래 코드는 재정의 없이 클래스 A의 두 인스턴스에 대한 hashCode를 출력하는 예제이다.

 

static class A{
  int a;
  public A(int a){this.a = a;}
}

public class Application{
  static void main(String[] args){
    A a1 = new A(1);
    A a2 = new A(1);

    System.out.println(a1.hashCode());  // 758529971
    System.out.println(a2.hashCode());  // 2104457164
  }
}

 

출력 결과물처럼 a1과 a2는 서로 다른 객체이기 때문에 재정의하지 않은 hashCode의 값은 내용에 상관없이, 주소를 기준으로 전혀 다른 객체로 인식하고 서로 다른 정수를 리턴한다.

 

 

String과 hashCode

 

반면 String 타입 객체의 hashCode는 객체의 주소가 아닌, 인스턴스의 멤버 값으로 객체를 구분하도록 재정의 되어 있다.  str1과 str2는 분명 서로 다른 객체임에도 불구하고, "hello"로 저장된 내용물이 같으므로 같은 코드 값을 반환한다. 

public class Application{
  static void main(String[] args){    
      String str1 = new String("hello");
      String str2 = new String("hello");
      
      System.out.println(str1.hashCode());      //99162322
      System.out.println(str2.hashCode());      //99162322
  }
}

 

 

HashCode 재정의

  

equals가 그랬 듯, 객체의 주소가 아닌 내용물 (멤버의 데이터)을 기준으로 식별 값을 리턴하려면 재정의가 필요하다. class A가 String 처럼 내부 인스턴스 변수 a의 값을 기준으로 hashCode를 반환하도록하려면 다음과 같이 구현할 수 있다. 

static class A{
    int a;
    public A(int a){this.a = a;}

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        A temp = (A)o;
        return a == temp.a;
    }

    @Override
    public int hashCode() {
        return Objects.hash(a);
    }
}

 

A타입 참조 변수 a1과 a2는, 실제 객체 주소는 다르나, a값이 1로 같으므로 동일한 해시 값을 얻을 수 있는 것이다.

 

public class Application{
  static void main(String[] args){
    A a1 = new A(1);
    A a2 = new A(1);

    System.out.println(a1.hashCode());  // 32
    System.out.println(a2.hashCode());  // 32
  }
}

 

따라서 새로운 객체를 정의할 때, 일반적인 것처럼 내용물을 기준으로 비교 / 해시 값 리턴을 필요로 한다면 잊지말고 equals와 hashCode를 재정의 해주어 한다.

 

 

System.identityHashCode(Object o)

 

  추가적으로 객체의 주소를 기준으로한 해시 값을 리턴 받고 싶다면 identityHashCode()를 사용할 수 있다. 아래 예시에서처럼 str1, str2, str3가 hello로 내용이 같지만, identityHashCode를 사용하면 서로 다른 해시 값을 리턴 받을 수 있다..

 

String str1 = new String("hello");
String str2 = new String("hello");

System.out.println(System.identityHashCode(str1)); // 758529971
System.out.println(System.identityHashCode(str2)); // 2104457164

String str3 = "hello";
String str4 = "hello";

System.out.println(System.identityHashCode(str3)); // 1521118594
System.out.println(System.identityHashCode(str4)); // 1521118594

 

str3와 str4의 identityHashCode가 같은 이유는 StringPool 때문이다.

잘모르겠다면 아래 글 참고.

 

 

자바 / equals와 비교 연산자의 차이 / String Pool

equals 지금까지 'equals는 내용 비교, 비교 연산자는 주소 비교' 정도로 얼버무려 생각하고 equals를 써왔다. Object가 포함하는 메소드를 살펴보면서 equals를 단순히 내용 비교라고 하기 찝찝하여, 지금 갖고..

ecsimsw.tistory.com

 

Comments