웹사이트 검색

자바 equals() 및 hashCode()


Java equals() 및 hashCode() 메서드는 Object 클래스에 있습니다. 따라서 모든 Java 클래스는 equals() 및 hashCode()의 기본 구현을 가져옵니다. 이 게시물에서는 java equals() 및 hashCode() 메서드를 자세히 살펴보겠습니다.

자바 equals()

객체 클래스 정의 equals() 메소드는 다음과 같습니다.

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

equals() 메소드의 자바 문서에 따르면 모든 구현은 다음 원칙을 준수해야 합니다.

  • 모든 객체 x에 대해 x.equals(x)true를 반환해야 합니다.
  • 두 객체 x와 y에 대해 x.equals(y)y.equals(x)true를 반환해야 합니다. >는 true를 반환합니다.
  • 여러 개체 x, y, z의 경우 x.equals(y)truey.equals(z)를 반환하는 경우 true를 반환하면 x.equals(z)true를 반환해야 합니다.
  • equals() 메서드 구현에서 사용 중인 개체 속성이 수정되지 않는 한 x.equals(y)를 여러 번 호출하면 동일한 결과가 반환되어야 합니다. .
  • 객체 클래스 equals() 메서드 구현은 두 참조가 모두 동일한 객체를 가리키는 경우에만 true를 반환합니다.

자바 해시코드()

Java 객체 hashCode()는 기본 메서드이며 객체의 정수 해시 코드 값을 반환합니다. hashCode() 메서드의 일반 계약은 다음과 같습니다.

  • hashCode()를 여러 번 호출하면 equals() 메서드에서 사용 중인 개체 속성이 수정되지 않는 한 동일한 정수 값을 반환해야 합니다.
  • 객체 해시 코드 값은 동일한 애플리케이션을 여러 번 실행하면 변경될 수 있습니다.
  • equals() 메서드에 따라 두 개체가 같으면 해당 해시 코드가 동일해야 합니다.
  • 두 개체가 equals() 메서드에 따라 같지 않으면 해시 코드가 다를 필요가 없습니다. 해시 코드 값은 같을 수도 있고 같지 않을 수도 있습니다.

equals() 및 hashCode() 메서드의 중요성

Java hashCode() 및 equals() 메서드는 데이터 저장 및 검색을 위해 Java의 해시 테이블 기반 구현에 사용됩니다. How HashMap works in java에서 자세히 설명했습니다. equals() 및 hashCode()의 구현은 다음 규칙을 따라야 합니다.

  • o1.equals(o2)인 경우 o1.hashCode() == o2.hashCode()는 항상 true여야 합니다.
  • o1.hashCode() == o2.hashCode가 true인 경우 o1.equals(o2)true<가 된다는 의미는 아닙니다..

equals() 및 hashCode() 메서드를 재정의해야 하는 경우는 언제입니까?

equals() 메서드를 재정의할 때 hashCode() 메서드도 재정의하여 계약이 구현에 의해 위반되지 않도록 해야 합니다. equals() 및 hashCode() 계약을 위반하는 경우 프로그램에서 예외가 발생하지 않으며 클래스를 해시 테이블 키로 사용하지 않을 경우 문제가 발생하지 않습니다. 클래스를 해시 테이블 키로 사용하려는 경우 equals() 및 hashCode() 메서드를 모두 재정의해야 합니다. equals() 및 hashCode() 메서드의 기본 구현에 의존하고 사용자 정의 클래스를 HashMap 키로 사용할 때 어떤 일이 발생하는지 살펴보겠습니다.

package com.journaldev.java;

public class DataKey {

	private String name;
	private int id;

        // getter and setter methods

	@Override
	public String toString() {
		return "DataKey [name=" + name + ", id=" + id + "]";
	}

}
package com.journaldev.java;

import java.util.HashMap;
import java.util.Map;

public class HashingTest {

	public static void main(String[] args) {
		Map<DataKey, Integer> hm = getAllData();

		DataKey dk = new DataKey();
		dk.setId(1);
		dk.setName("Pankaj");
		System.out.println(dk.hashCode());

		Integer value = hm.get(dk);

		System.out.println(value);

	}

	private static Map<DataKey, Integer> getAllData() {
		Map<DataKey, Integer> hm = new HashMap<>();

		DataKey dk = new DataKey();
		dk.setId(1);
		dk.setName("Pankaj");
		System.out.println(dk.hashCode());

		hm.put(dk, 10);

		return hm;
	}

}

위의 프로그램을 실행하면 null이 출력됩니다. 키를 찾을 버킷을 찾는 데 Object hashCode() 메서드를 사용하기 때문입니다. HashMap 키에 액세스할 수 없고 데이터를 검색하기 위해 키를 다시 생성하므로 두 개체의 해시 코드 값이 다르므로 값을 찾을 수 없습니다.

equals() 및 hashCode() 메서드 구현

@Override
public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result + id;
	result = prime * result + ((name == null) ? 0 : name.hashCode());
	return result;
}

@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (obj == null)
		return false;
	if (getClass() != obj.getClass())
		return false;
	DataKey other = (DataKey) obj;
	if (id != other.id)
		return false;
	if (name == null) {
		if (other.name != null)
			return false;
	} else if (!name.equals(other.name))
		return false;
	return true;
}

equals() 및 hashCode() 메서드 모두 계산에 동일한 필드를 사용하므로 해당 계약이 유효한 상태로 유지됩니다. 테스트 프로그램을 다시 실행하면 맵에서 개체를 가져오고 프로그램은 10을 인쇄합니다. 또한 Project Lombok을 사용하여 equals 및 hashCode 메서드 구현을 자동 생성할 수 있습니다.

해시 충돌이란 무엇입니까

매우 간단한 용어로 Java 해시 테이블 구현은 가져오기 및 넣기 작업에 대해 다음 논리를 사용합니다.

  1. 먼저 "키\ 해시 코드를 사용하여 사용할 "버킷\을 식별합니다.
  2. 해시 코드가 동일한 버킷에 개체가 없으면 넣기 작업을 위한 개체를 추가하고 가져오기 작업을 위해 null을 반환합니다.
  3. 버킷에 동일한 해시 코드를 가진 다른 개체가 있는 경우 "key\ equals method가 작동합니다.\n
    • equals()가 true를 반환하고 put 작업이면 개체 값이 재정의됩니다.
    • equals()가 false를 반환하고 put 작업이면 새 항목이 버킷에 추가됩니다.
    • equals()가 true를 반환하고 get 작업이면 개체 값이 반환됩니다.
    • equals()가 false를 반환하고 get 작업이면 null이 반환됩니다.

hashCode()와 equals()를 모두 구현하지 않으면 어떻게 될까요?

위에서 hashCode()가 구현되지 않으면 HashMap이 해시 코드를 사용하여 항목을 찾을 버킷을 찾기 때문에 값을 검색할 수 없다는 것을 이미 살펴보았습니다. hashCode()만 사용하고 equals()를 구현하지 않으면 equals() 메서드가 false를 반환하기 때문에 값도 검색되지 않습니다.

equals() 및 hashCode() 메서드 구현을 위한 모범 사례

  • equals() 및 hashCode() 메서드 구현에서 동일한 속성을 사용하여 속성이 업데이트될 때 계약을 위반하지 않도록 합니다.
  • 호출할 때마다 해시 코드를 계산하는 것보다 해시 코드를 캐시할 수 있도록 변경 불가능한 객체를 해시 테이블 키로 사용하는 것이 좋습니다. 그렇기 때문에 문자열은 변경할 수 없고 해시 코드 값을 캐시하기 때문에 해시 테이블 키로 좋은 후보입니다.
  • 최소한의 해시 충돌이 발생하고 항목이 모든 버킷에 고르게 분산되도록 hashCode() 메서드를 구현합니다.

GitHub 리포지토리에서 전체 코드를 다운로드할 수 있습니다.