Objects.hash()와 Objects.hashCode()의 차이점을 공부하고 기록한 글입니다.
hashcode는 객체의 내용을 숫자로 표현한 것입니다.
Java에는 hascode를 얻기 위한 메서드가 여럿 있습니다.
내부 구현
public static int hashCode(Object o) {
return o != null ? o.hashCode() : 0;
}
int one = Objects.hashCode("1"); // 49
int otherOne = Objects.hashCode("1"); // 49
같은 값을 전달하면 같은 해시코드를 리턴합니다.
@IntrinsicCandidate
public native int hashCode();
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;
}
정리해 보면 Objects.hash("1")과 Objects.hashCode("1")은 같은 값을 리턴하지 않는다는 것을 확인할 수 있습니다. Objects.hash() 메서드에서는 추가적인 연산이 들어가기 때문입니다.
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);
이 글에서는 Object.hashCode(), Objects.hashCode 그리고 Objects.hash()를 사용하는 법을 살펴봤습니다. 생각 없이 사용하던 hashcode 관련 메서드를 정리하는 좋은 기회가 되었습니다.
각 메서드의 기능을 요약하며 글을 마치겠습니다.
| name | 호출 전 null 체크 필요 | 파라미터 수 |
|---|---|---|
| Object.hashCode() | 필요 | 파라미터 없음 |
| Objects.hashCode() | 필요 없음 | 단일 파라미터 |
| Objects.hash() | 필요 없음 | 복수 파라미터 |