Objects.hash() 그리고 Objects.hashCode()

hwibaski·2023년 10월 13일

Java

목록 보기
7/7

1. 들어가며

Objects.hash()와 Objects.hashCode()의 차이점을 공부하고 기록한 글입니다.

hashcode는 객체의 내용을 숫자로 표현한 것입니다.
Java에는 hascode를 얻기 위한 메서드가 여럿 있습니다.

  • Object.hashCode()
  • Objects.hashCode() - since Java 7
  • Objects.hash() - since Java 7

2. 기본 사용법

2-1. Objects.hashCode()

내부 구현

public static int hashCode(Object o) {
    return o != null ? o.hashCode() : 0;
}
  • hashCode를 리턴하는데 null 처리가 되어 있습니다.
  • 결국 Object의 hashCode()를 리턴합니다.
int one = Objects.hashCode("1");      // 49
int otherOne = Objects.hashCode("1"); // 49

같은 값을 전달하면 같은 해시코드를 리턴합니다.

2-2. Object.hashCode()

 @IntrinsicCandidate
 public native int hashCode();
  • native 키워드는 해당 메서드가 JNI를 사용해서 네이티브로 구현되었음을 나타냅니다.

2-3. Objects.hash()

public static int hash(Object... values) {
    return Arrays.hashCode(values);
}
public static int hashCode(Object a[]) {
    if (a == null)
        return 0;

    int result = 1;

    for (Object element : a)
        result = 31 * result + (element == null ? 0 : element.hashCode());

    return result;
}
  • 매개변수로 가변인자, varargs를 받습니다.
  • null 예외처리가 되어있습니다. a[] 자체가 null 인 경우와 a의 요소들이 null일 경우도 체크해주고 있습니다.
  • 코드가 조금 있지만 결국 매개변수로 같은 값들이 들어오면 같은 해시코드를 반환합니다.

정리해 보면 Objects.hash("1")과 Objects.hashCode("1")은 같은 값을 리턴하지 않는다는 것을 확인할 수 있습니다. Objects.hash() 메서드에서는 추가적인 연산이 들어가기 때문입니다.

3. 차이점

Baeldung 블로그 참고

Objects.hash()와 Objects.hashCode()의 차이점을 살펴보기 위해서 Player라는 샘플 클래스를 만들겠습니다.

public class Player {
    private String firstName;
    private String lastName;
    private String position;

    // Standard getters/setters
}

Player 객체의 각 필드가 같으면 두 개의 객체는 동등하다고 볼 때, hashCode()를 어떻게 오버라이딩 할 수 있을까요? 특히 Objects.hashCode()와 Objects.hash() 메서드를 사용하지 않고 말이죠.

Java7 이전에는 아래와 같이 구현을 했습니다. 직접 null 체크를 하고 hashCode의 세부 구현을 작성했다고 합니다.

여기서 31이 나오는 이유에 대한 글은 링크를 확인

@Override
public int hashCode() {
    int result = 17;
    result = 31 * result + firstName != null ? firstName.hashCode() : 0;
    result = 31 * result + lastName != null ? lastName.hashCode() : 0;
    result = 31 * result + position != null ? position.hashCode() : 0;
    return result;
}

위의 코드에서 Objects.hashCode()의 null 안정성을 활용하여 코드를 단축할 수 있습니다.

int result = 17;
result = 31 * result + Objects.hashCode(firstName);
result = 31 * result + Objects.hashCode(lastName);
result = 31 * result + Objects.hashCode(position);
return result;

마지막으로 Objects.hash()를 이용하여 위의 코드를 더 단축할 수 있습니다. 위쪽 글에서 Objects.hash()의 내부 구현에는 null 체크와 함께 hashcode를 계산해 주는 로직이 이미 들어가 있습니다.

return Objects.hash(firstName, lastName, position);

특이하면서 재밌는 사항은 아래의 코드에서 hashCode1과 hashCode2의 값이 같습니다. 그도 그럴 것이 Objects.hash()의 내부 구현의 Arrays.hashCode()이기 때문이죠.

    Player player = new Player("Bobby", "Dalbec", "First Base");
    int hashcode1 = player.hashCode();
    String[] playerInfo = {"Bobby", "Dalbec", "First Base"};
    int hashcode2 = Arrays.hashCode(playerInfo);
        
    assertEquals(hashcode1, hashcode2);

4. 정리하며

이 글에서는 Object.hashCode(), Objects.hashCode 그리고 Objects.hash()를 사용하는 법을 살펴봤습니다. 생각 없이 사용하던 hashcode 관련 메서드를 정리하는 좋은 기회가 되었습니다. 

각 메서드의 기능을 요약하며 글을 마치겠습니다.

name호출 전 null 체크 필요파라미터 수
Object.hashCode()필요파라미터 없음
Objects.hashCode()필요 없음단일 파라미터
Objects.hash()필요 없음복수 파라미터

reference

Java Objects.hash() vs Objects.hashCode()

0개의 댓글