이번 글에서는 HashMap과 HashSet의 차이에 대해 알아보겠습니다.
HashMap은 키와 값을 저장하고, HashSet은 고유한 키 값만을 저장합니다.
그렇기 때문에, HashMap은 value에 있어 중복을 허용하지만, HashSet은 중복을 허용하지 않습니다.
자바에서 해시맵은 Node객체의 배열을 저장소로 활용합니다.
Node클래스는 해싱한 결과값, 키, 값, 다음노드를 가리키기 위한 node객체를 필드로 가집니다.


key로 들어온 값을 해싱하고, 배열의 인덱스로 사용해서 값을 집어넣습니다. 
위에서 HashMap 은 데이터를 저장하기 위해 배열을 사용한다고 말했습니다.
이때, 해시값을 배열 크기에 맞게 조정하지 않으면 해시값이 너무 커, 배열의 크기를 초과하는 인덱스를 가리킬 수 있습니다.
따라서, 해시값을 배열의 크기 안으로 변환하기 위해서 mod연산이나 비트연산을 합니다.
해시함수 코드는 다음과 같습니다.

코드를 보면, key가 null이면 0을 반환하고, key가 null이 아니라면 해시함수를 통해 해시값을 생성해 준 이후, 비트연산 이후 xor연산을 수행하는것을 확인할 수 있습니다.
HashSet은 고유한 원소들의 집합을 저장하는 자료구조로, 중복된 값을 허용하지 않습니다. 내부적으로 HashMap 을 사용하여 구현되기 때문에, 모든 원소는 HashMap의 키로 저장회며 값은 더미객체로 설정됩니다.
다음과 같이 HashSet 클래스는 HashMap 을 사용합니다.

HashSet은 내부적으로 HashMap으로 동작된다고 말 했습니다. 그렇지만, 우리가 넣는 값은 key값 뿐입니다. 그렇기 때문에, HashMap을 동작시킬 dummy객체가 필요합니다.

HashMap<E, Object> 에서 E는 HashSet이 저장하는 원소의 타입이고, Object는 모든 원소에 동일한 값을 할당하기 위한 자료형으로 더미객체가 들어갑니다.
PRESENT는 HashSet이 내부적으로 사용하는 더미객체로, new Object() 를 통해 생성된 빈 객체입니다.
이 객체는 실제 데이터와는 관련이 없지만, HashSet는 내부적으로 HashMap으로 동작하기 때문에, HashMap의 동작을 위해 생성한 객체입니다.

위와 같이 Object 안에는 모두 PRESENT라는 값이 들어갑니다.
정리표는 아래와 같습니다.
| HashSet | HashMap | |
|---|---|---|
| 용도 | 고유한 원소들의 집합 | key-value 의 쌍을 저장 |
| 구조 | 내부적으로 HashMap을 사용 | 해시테이블 기반 자료구조 |
| 데이터 저장 | key만 저장. 내부적으로 HashMap을 사용하므로, 삽입되는 객체(key)와 dummuy 객체(value값)을 생성함 | key-value 쌍을 모두 저장. 삽입연산동안 단 하나의 객체가 생성 |
| 중복여부 | 중복 원소를 허용하지 않음 | Key: 중복X / value: 중복O |
| 구현 | Set의 구현체 | Map의 구현체 |
| 속도 | HashMap보다 느리다 | HashSet보다 빠르다 |