HashSet의 중복 처리?

zini9188·2023년 1월 10일

추가공부

목록 보기
3/4

목표

사용자 정의 클래스의 인스턴스를 HashSet에 저장하는 과정 중 중복 입력값이 제거되지 않는 일이 생겼다. 이유가 무엇인지 알아보는 과정에서 HashSet의 중복 처리 과정을 알아보게 되었다.


Hash값을 사용하는 Collection의 작동 원리

  • hash값을 사용하는 Collection(HashSet, HashMap, HashTable)은 eqaulshashCode 메서드를 통해 논리적으로 같은지를 비교한다.

  • hashCodeequals 모두를 재정의 해야 하는 이유는 다음과 같다.

  • 그림에서 보이듯 hashCode만 정의하면 false값이 들어왔을 때 다른 객체임을 알 수 있다.

  • 그렇다면 equals가 정의되어 있지 않으면 해당 과정을 건너뛰고 동등 객체임을 알려줄까?

hashCode만 재정의할 경우

public class HashPerson {
    private String name;
    private int age;

    public HashPerson(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

    @Override
    public boolean equals(Object obj) {
        if(obj == this) return true;        
        if(obj == null || obj.getClass() != getClass()) return false;        
        HashPerson hashPerson = (HashPerson) obj;
        return Objects.equals(name, hashPerson.name);
    }
}
public static void main(String[] args) {
	HashSet<HashPerson> hashPeople = new HashSet<>();
    hashPeople.add(new HashPerson("유재석", 50));
    hashPeople.add(new HashPerson("유재석", 50));
    
    for (HashPerson hashPerson : hashPeople) {
    	System.out.println(hashPerson + " " + hashPerson.hashCode());
    }
}        
{유재석, 50} 50622000
{유재석, 50} 50622000
  • 해쉬값은 같지만 equals가 없어 동등 객체임을 알지 못하는 것 같다.

equals만 재정의할 경우

  • hashCode없이 equals만 정의한 결과이다.
@Override
public boolean equals(Object obj) {
	if (this == obj) return true;
    if (obj == null || obj.getClass() != getClass()) return false;
    HashPerson hashPerson = (HashPerson) obj;
    return Objects.equals(name, hashPerson.name);
}
{유재석, 50} 884457408
{유재석, 50} 1740035246
  • 이번엔 equals를 추가하였지만 두 hash값이 달라 동등 객체임을 판단하지 못하는 것 같다.

hash값이 다른 이유

  • hashCode 메서드가 정의되어 있지 않아 Object 클래스의 hashCode 메서드가 사용되는데 이는 객체의 고유한 주소 값을 int값으로 변환한다고 한다

두개 모두 정의하는 경우

{유재석, 50} 1569282050
  • 정상적으로 중복이 제거가 되었다.

  • 결국 그림의 과정처럼 hashCode의 리턴값이 일치하며 equlas메서드의 리턴 값이 true를 반환해야 논리적으로 동등 객체임을 판단한다는 사실을 알았다.

hashCode()의 추가 사실


Objects.hash() 메서드는 hashCode 메서드를 재정의하기 위해 간편히 사용할 수 있는 메서드이지만 속도가 느리다고 한다.
인자를 담기 위한 배열이 만들어지고 인자 중 기본 타입이 있다면 박싱과 언박싱을 거쳐야 하기 때문이라고 한다.

성능에 민감한 프로그램은 단순하게 Objects.hash() 메서드를 이용하여 재정의하여도 되지만 민감한 경우에는 직접 재정의 하는 것이 좋다고 한다. 관련링크


참조 블로그

profile
똑같은 짓은 하지 말자

0개의 댓글