equals 를 재정의 하려거든 hashCode 도 재정의하라
핵심 : equals 를 재정의한 클래스는 모두 hashCode 도 재정의해야한다.
이유 : 만약 재정의 해주지 않는다면, 논리적으로 같은 객체는 같은 해시코드를 반환해야 한다는 해시코드 규약을 위반하게 되어, HashMap 이나 HashSet 과 같이 hashCode 를 활용하는 클래스에서 문제가 생길 수 있기 때문이다.
클래스에서 equals 를 재정의 한다는 것은 일반적으로 동일성 보다 동등성으로 객체를 비교하고자 함을 의미한다.
equals 와 함께 hashCode 를 재정의 해주지 않으면 논리적으로 같은 객체이지만 다른 hashCode 를 가지게 되므로 hashCode 를 활용하는 클래스에서 문제가 생길 수 있습니다.
같다고 정의한 인스턴스는 반드시 같은 해시코드가 나와야하고 서로 다른 인스턴스는 가능한 서로 다른 해시코드가 나와야한다.
public class Rectangular {
int width ;
int length ;
public Rectangular (int width , int length ) {
this .width = width ;
this .length = length ;
}
@ Override
public boolean equals (Object o ) {
if (this == o ) {
return true ;
}
if (o == null || getClass () != o .getClass ()) {
return false ;
}
Rectangular that = (Rectangular ) o ;
return width == that .width && length == that .length ;
}
}
public static void main (String [] args ) {
Rectangular rec1 = new Rectangular (20 , 30 );
Rectangular rec2 = new Rectangular (20 , 30 );
System .out .println (rec1 .hashCode ()); //1975358023
System .out .println (rec2 .hashCode ()); //2101440631
}
좋은 hashCode() 메서드를 만드는 법
같다고 정의한 인스턴스는 반드시 같은 해시코드가 나와야하고 서로 다른 인스턴스는 가능한 서로 다른 해시코드가 나와야한다.
equals 를 정의할 때 사용했던 필드를 핵심 필드라고 하고, 해시코드를 생성 할 때 핵심 필드만 사용해서 조합 하는 것이 제일 좋다.
핵심 필드 각각의 해시코드 값들을 연산하여 객체의 해시코드를 만든다.
연산은 단순하면서도 연산 순서를 이용해서 같은 해시코드가 나올 가능성을 낮추는 것이 좋다.
@ Override
public int hashCode () {
int result = Integer .hashCode (width );
result = 31 * result + Integer .hashCode (length );
return result ;
}
public static void main (String [] args ) {
Rectangular rec1 = new Rectangular (20 , 30 );
Rectangular rec2 = new Rectangular (20 , 30 );
System .out .println (rec1 .hashCode ()); //650
System .out .println (rec2 .hashCode ()); //650
}
@ Override
public int hashCode () {
return Objects .hash (width , length );
}
}