▸JAVA/기본 문법

객체의 등가성(객체 비교)_hashCode 메소드 [4/4]

코데방 2019. 12. 10.
728x90

[ hashCode 메소드 ]

  • 객체 내부의 필드 값을 hash값으로 바꿔 hash값을 리턴해줌
  • 같은 값은 무조건 동일 hash값을 가짐
  • 하지만 hash값이 동일하더라도 값이 다를 수 있기 때문에 equals 메소드와 혼용 필수
  • equals 메소드보다 비교 연산이 빠르기 때문에 hashCode를 먼저 비교 후 equals 수행

동일한 객체는 무조건 같은 hash값을 가지지만 낮은 확률로 서로 다른 두 객체가 같은 hash값을 가질 수도 있습니다. 따라서 hashCode 메소드를 통해 동일한 hash값이 도출되면 equals 메소드를 다시 수행해 값을 비교해줍니다. 이렇게 하는 이유는 hash값을 도출하는 연산이 더 빨라서 값이 다른 객체는 대부분 hashCode에서 걸러낼 수 있기 때문입니다. 추가로 같은 값을 대상으로 비교해줘야 문제가 없기 때문에 equals의 비교 대상과 hashCode의 비교대상은 동일하게 셋팅해줘야 합니다.

 


 

hashCode 메소드 또한 equals와 마찬가지로 가장 기본적인 Object 클래스에서 상속되어 가지고 있는 메소드 중 하나입니다. 역시 마찬가지로 기본 메소드에서는 객체가 다르면 다른 hash값을 반환해서 비교가 어렵기 때문에 따로 오버라이딩 해줘야 합니다. 아래는 오버라이딩 전 기본 hash값을 받아온 결과입니다. 문자열에 대한 해시값(a.hashCode()의 결과)은 같지만 객체에 대한 해시값은 다르게 나와 비교가 되지 않습니다.

 

문자열의 hashCode()의 값이 똑같이 나온 이유는, 문자열 클래스에서 문자열 객체의 주소가 아닌 값으로 비교하게끔 오버라이딩 되어 있기 때문입니다. 따라서 필요한 클래스에서도 같은 방식으로 오버라이딩 해줘야 합니다. 

 

package study.first;

public class Main {

	public static void main(String[] args) {

		Sub s1 = new Sub();
		s1.a = "abc";
		Sub s2 = new Sub();
		s2.a = "abc";
		System.out.println(s1.a.hashCode());
		System.out.println(s2.a.hashCode());
		
		System.out.println(s1.hashCode());
		System.out.println(s2.hashCode());
		
	}
}

 


 

아래는 이클립스에서 생성해준 hashCode 메소드 코드입니다. 같은 값을 가진 객체가 같은 해시값을 가지게 됩니다. 간단한 규칙을 통해 해시값을 생성하고 있으며, 조금 더 복잡한 규칙을 원하면 수정해서 써도 무방합니다. 다만 보안상의 이유가 아니고 단순 비교 목적이라면 해당 코드만으로도 충분할 것 같습니다.

 

package study.first;

public class Main {

	public static void main(String[] args) {

		Sub s1 = new Sub();
		s1.a = "abc";
		Sub s2 = new Sub();
		s2.a = "abc";
		System.out.println(s1.a.hashCode());
		System.out.println(s2.a.hashCode());
		
		System.out.println(s1.hashCode());
		System.out.println(s2.hashCode());
		
	}
}

/* Sub 클래스 */
class Sub {

	int x;
	String a;
	
	@Override
	public int hashCode() {

		final int prime = 31;
		int result = 1;
		result = prime * result + ((a == null) ? 0 : a.hashCode());	
		// 문자열 있으면 문자열의 해시코드를 더해줌
		
		result = prime * result + x;
		// 다시 한 번 더 prime값을 써서 값을 변경하고 정수값을 더해줌
		return result;
	}		
}

 


 

위에서 설명했듯이, equals 전에 먼저 hashCode를 통해 객체 비교를 진행하는 이유는 속도 때문입니다. equals 메소드는 값을 하나씩 비교해서 검증하기 때문에 시간이 걸리는 반면, 해시값은 간단한 계산의 결과만 가지고 비교하기 때문에 상대적으로 비교 속도가 빠릅니다. 객체 안의 필드값이 많을 수록 속도 차이가 많이 나게 됩니다.

참고로 혹시 이클립스나 IDE의 도움 없이 직접 hashCode 메소드를 오버라이딩 해야하는 경우, Objects.hash 메소드를 이용해서 간단히 구성할 수 있습니다. 비교할 필드만 인자값으로 넣어주면 해당 변수에 맞는 해시값을 만들어줍니다.

 

package study.first;

import java.util.Objects;

public class Main {

	public static void main(String[] args) {

		Sub s1 = new Sub();
		s1.a = "abc";
		Sub s2 = new Sub();
		s2.a = "abc";
		System.out.println(s1.a.hashCode());
		System.out.println(s2.a.hashCode());
		
		System.out.println(s1.hashCode());
		System.out.println(s2.hashCode());
		
	}
}

/* Sub 클래스 */
class Sub {

	int x;
	int y;
	String a;
	
	@Override
	public int hashCode() {

		return Objects.hash(this.x, this.a);
	}	
}
728x90

댓글

💲 추천 글