hashCode
equals 처럼 hashCode도 Object 클래스부터 정의되어있는 공통 메소드이다. hashCode는 일반적으로 객체를 비교하기 전에 간략히 비교할 대상을 걸러내는 용도로 사용된다. hashCode역시 공통 메소드로서 지켜야하는 공통 규약이 존재한다.
1. equals에 사용되는 정보가 변경되지 않는다면, hashCode의 값도 일정해야 한다.
2. equals 비교 결과 true인 두 객체는 hashCode의 값도 같아야 한다.
3. equals 비교 결과 false인 두 객체의 hashCode 값이 꼭 달라야 하는건 아니다.
hashCode의 역할
public class Customer {
private String customerId;
public Customer(String customerId) {
this.customerId = customerId;
}
@Override
public boolean equals(Object obj) {
if(obj == this)
return true;
if(!(obj instanceof Customer))
return false;
return this.getCustomerId().equals(((Customer) obj).getCustomerId());
}
...
}
// equals 비교하면 true가 나오는 두 객체이지만 Set 객체의 contains는 false가 나온다.
Customer customer1 = new Customer("0001");
Customer customer2 = new Customer("0001");
Set<Customer> signedCustomer = new HashSet<Customer>();
signedCustomer.add(customer1);
System.out.println(signedCustomer.contains(customer2));
Set 인터페이스의 HashSet는 객체들을 보관하고 있다가 해당 객체가 포함되어있는지 확일 할 수 있다. 하지만 위의 코드에서 논리적으로 동일한 customer1, customer2 두 객체가 존재하지만 customer1 객체를 HashSet에 넣고 customer2 객체가 존재하는지 contains를 호출할 결과 false가 나온다. HashSet는 기존에 해당 객체가 존재하는지 확인하기 위해 equals로 비교를 한다. 하지만 효율적인 비교를 위해 hashCode의 값을 먼저 비교해보고 hashCode가 같은 경우에만 equals 비교를 한다. 위 코드는 hashCode 2번 규약을 지키지 않아서 문제가 발생한 경우이다.
올바른 hashCode 정의
다음은 책에서 소개하는 올바른 hashCode 메소드를 만드는 방법은 아래와 같다.
1. int형 result를 선언하고 equals 비교에 사용하는 핵심필드의 hashCode 값으로 초기화한다.
2. result = result * 31 + (equals 비교에 사용하는 나머지 필드의 값의 hashCode)
3. result 반환
public class Customer {
...
@Override
public int hashCode() {
int result = customerId.hashCode();
return result;
}
...
}
추가내용
// Objects 클래스의 hash를 사용할 수 있으나 성능이 떨어진다.
public class Customer {
...
@Override
public int hashCode() {
return Objects.hash(customerId);
}
...
}
// hashCode를 캐시해두고 계속 사용하는 방식. 성능은 좋으나 주의해서 사용해야한다.
public class Customer {
private String customerId;
private int hashCode;
...
public String getCustomerId() {
if(hashCode == 0) {
hashCode = customerId.hashCode();
}
return hashCode;
}
...
}
+lombok
lombok을 사용하고 있다면 @EqualsAndHashCode 어노테이션을 사용하면 된다.
@EqualsAndHashCode
public class Customer {
private String customerId;
public Customer(String customerId) {
this.customerId = customerId;
}
...
}
'STUDY > 이펙티브자바' 카테고리의 다른 글
3-4) clone 재정의는 주의해서 진행하라 (0) | 2022.09.01 |
---|---|
3-3) toString을 재정의 하라 (0) | 2022.08.31 |
3-1) equals는 일반 규약을 지켜서 재정의하라 (0) | 2022.08.25 |
2-9) try-finally 보다는 try-with-resources를 사용하라 (0) | 2022.08.23 |
2-8) finalizer와 cleaner 사용을 피하라 (0) | 2022.08.22 |