본문 바로가기
JAVA BASE/Collection(컬렉션) - 자료구조

10. [자바] HashSet이 중복값을 제거하지 못할 때

by staticClass 2021. 1. 4.

HashSet의 add메소드의 진실

HashSet의 add메소드는 새로운 요소를 추가하기 전에 기존 노드와 가튼 것인지 판별하기 위한 작업으로

추가하려는 노드의 eqauls()와 hashCode()를 호출하게 된다.

equals()와 hashCode()의 부재

import java.util.HashSet;

public class HashSetTest {
	public static void main(String[] args) {
		HashSet set = new HashSet(); 
		
		set.add("123");
		set.add("123");
		set.add(new Person("KimJava", 100)); // ↓동일↓
		set.add(new Person("KimJava", 100)); // ↑동일↑
		
		System.out.println(set);
	}
}

class Person{
	String name;
	int age;
	
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public String toString() {
		return name + ":" + age;
	}
}
[abc, KimJava:100, KimJava:100]

위의 코드에서 Person 인스턴스를 new Person("KimJava", 100) 으로 2번 만들었다.

생각대로 라면 name(이름)과 age(나이)가 같으면 같은 사람으로 인식하도록 하였지만

Set에서 같은 사람으로 인식하지 않고 KimJava:100이 2번 출력되었다.

 

이 이유는 위에서 설명했듯이 add가 새로운 요소를 추가하기 전에 기존 노드와 가튼 것인지 판별하기 위한 작업으로

추가하려는 노드의 eqauls()와 hashCode()를 호출하게 되는데 이 두 메서드가 오버라이딩 되어 있지 않기 때문에

이런 결과가 나왔다.

 

equals()와 hashCode()의 오버라이드

import java.util.HashSet;
import java.util.Objects;

public class HashSetTest{
	public static void main(String[] args) {
		HashSet set = new HashSet();
		
		set.add(new String("abc"));
		set.add(new String("abc"));
		set.add(new Person("KimJava", 100));
		set.add(new Person("KimJava", 100));
		
		System.out.println(set);
	}
}

class Person {
	String name;
	int age;
	
	Person(String name, int age){
		this.name = name;
		this.age = age;
	}
    
	//equals를 오버라이딩 해주었다.
	public boolean equals(Object obj) {
		if(obj instanceof Person) {
			Person tmp = (Person)obj;
			return name.equals(tmp.name)  && age==tmp.age;
		}
		return false;
	}
    
	//hashCode를 오버라이딩 해주었다.
	public int hashCode() {
		return Objects.hash(name, age);
	}
	
	public String toString() {
		return name + ":" + age;
	}
}
[abc, KimJava:100]

위와 같이 equals()와 hashCode()를 오버라이드 해주었더니 원하던 값이 출력됐다.

 

hashChde()를 오버라이딩 할때의 세가지 조건

1. 실행 중인 애플리케이션 내의 동일한 객체에 여러번 hashCode()를 호출해도 동일한 int값을 반환해야 한다.
2. equals메서드를 이용한 비교에 의해서 true를 얻은 두 객체에 대해
각각 hashCode()를 호출해서 얻은 결과는 반드시 같아야 한다.
3. equals메서드를 호출했을 때 false를 반환하는 두 객체는 hashCode() 호출에 대해
같은 int값을 반환하는 경우가 있어도 괜찮지만, 해싱(hashing)을 사용하는 컬렉션의 성능을 향상시키기 위해서는
다른 int값을 반환하는 것이 좋다

댓글