자바 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)
가true
및y.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 해시 테이블 구현은 가져오기 및 넣기 작업에 대해 다음 논리를 사용합니다.
- 먼저 "키\ 해시 코드를 사용하여 사용할 "버킷\을 식별합니다.
- 해시 코드가 동일한 버킷에 개체가 없으면 넣기 작업을 위한 개체를 추가하고 가져오기 작업을 위해 null을 반환합니다.
- 버킷에 동일한 해시 코드를 가진 다른 개체가 있는 경우 "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 리포지토리에서 전체 코드를 다운로드할 수 있습니다.