[java2] #16 - HashSet
HashSet
- Set 인터페이스에서 지원하는 구현 클래스로 순서에 의미를 두지 않으며 데이터의 중복이 없다.
(내부적으로 HashMap을 사용하여 구현되었기 때문에 어찌보면 당연한 이야기다.)
순서에 의미를 두지 않기 때문에 get(), set() 메서드가 제공되지 않는다.
- HashSet은 객체를 저장(add) 하기 전 먼저 객체의 hashCode() 메소드를 호출해서 해시코드를 얻은 다음
저장되어있는 객체들의 해시 코드와 비교한 뒤 같은 해시코드가 있다면 다시 equals() 메소드로 두 객체를
비교해 true가 나오면 동일한 객체로 판단하고 중복 저장을 하지 않는다.
- 오직 객채(Object)만 저장 가능하며, 그래서 HashMap보다 느리다.
왜냐하면 HashMap은 삽입되는 데이터의 형태가 각 Value들이 Unique한 Key에 mapping 되어 있지만,
HashSet은 삽입되는 object를 Key값으로, 내부 구현 코드에서 필드로 선언한 객체를 Value값으로 사용하기 때문에
해당 필드 객체의 해시 값 계산도 해야 하기 때문이다.
HashSet과 HashMap의 차이점
HashMap | HashSet | |
정의 | Map 인터페이스의 구현체로 HashTable과 유사한 자료구조로 데이터를 저장한다. | Set 인터페이스의 구현체로 내부적으로 HashMap을 사용하기 때문에 HashTable과 유사한 자료구조로 데이터를 저장한다. |
데이터 저장형태 | Key-Value 쌍 형태로 데이터를 저장하며, Key와 Value의 mapping을 유지하고 있다. | 객체 그 자체를 저장한다. 위에서 HashMap을 내부적으로 사용한다고 했는데, Key 값으로는 삽입되는 객체 그 자체를, Value 값으로는 HashSet 내부 구현 코드에서 미리 선언해둔 dummy 객체를 사용한다. |
중복 허용 여부 | 중복 Key 값을 허용하지 않지만, 중복 Value 값은 허용한다. | 객체 자체를 데이터로 저장하기 때문에 중복을 허용하지 않는다. |
NULL 허용 여부 | 중복 Key 값을 허용하지 않기 때문에 단 하나의 NULL 값을 Key 값으로 가질 수 있고, 여러 NULL 값을 Value 값으로 가질 수 있다. | 단 하나의 NULL 값을 가질 수 있다. |
데이터 삽입 방법 | put() 메서드를 사용하여 데이터를 삽입하는데, Key-Value 쌍 데이터의 형태를 저장하기 때문에 삽입 연산 동안 단 하나의 객체가 생성된다. |
add() 메서드를 사용하여 데이터를 삽입하는데, 객체 그 자체를 저장하고 내부적으로 HashMap을 사용하기 때문에 삽입되는 객체(Key값)와 dummy 객체(Value 값), 총 두 개의 객체가 삽입 연산 동안 생성된다. |
성능 | HashSet보다 빠르고 더 선호된다. |
1. 변수 선언
HashSet<데이터 타입> 변수명 = new HashSet<데이터 타입>();
*데이터 타입에는 String, Integer형의 HashMap 데이터가 들어간다.
HashSet<Integer> set = new HashSet<Integer>();
HashSet<String> set2 = new HashSet<String>();
출처: https://crazykim2.tistory.com/474 [차근차근 개발일기+일상:티스토리]
2. add() : 값 추가
값을 추가하는 방법은 add(value)를 사용해 추가한다. 데이터 타입에 맞는 데이터만 추가해야한다.
같은 객체를 2번 이상 넣으면 중복되는 데이터로 인식해 저장하지 않는다.
하지만 new를 사용해서 객체를 생성하면 기존에 생성되었던 객체와 내용이 같더라도 다른 hashcode가 부여되는데 HashSet, TreeSet은 중복되는 데이터 판단을 hashcode로 하기때문에 내용이 같더라도 다른 hashcode를 가지면 다른 객체로 취급해 같은 내용이라도 저장한다.
이 때 저장된 내용이 같을때 같은 객체로 취급하게 하려면 hashcode() 메서드를 Override 해서 내용이 같은 객체는 같은 hashcode를 가지게 하면 된다.
public class HashSetTest {
public static void main(String[] args) {
// Integer
HashSet<Integer> set = new HashSet<Integer>();
set.add(1);
set.add(2);
set.add(3);
set.add(1);
// String
HashSet<String> set2 = new HashSet<String>();
set2.add("a");
set2.add("b");
set2.add("c");
set2.add("a");
}
}
3. remove(), clear() : 값 삭제
remove(value)를 사용해 삭제한다. 원하는 값만 삭제할 수 있고
전부 삭제하고 싶을 경우 clear() 메서드를 사용한다.
public class HashSetTest {
public static void main(String[] args) {
// Integer
HashSet<Integer> set = new HashSet<Integer>();
set.remove(1);
set.clear();
// String
HashSet<String> set2 = new HashSet<String>();
set2.remove("a");
set2.clear();
}
}
4. size() : 크기 구하기
size() 메서드를 사용해 현재 HashSet의 크기를 구할 수 있다.
중복값이 들어오면 자동으로 제거된다.
public class HashSetTest {
public static void main(String[] args) {
// Integer
HashSet<Integer> set = new HashSet<Integer>();
set.add(1);
set.add(2);
set.add(3);
set.add(1);
System.out.println("set의 크기 : " + set.size());
// String
HashSet<String> set2 = new HashSet<String>();
set2.add("a");
set2.add("b");
set2.add("c");
set2.add("a");
System.out.println("set2의 크기 : " + set2.size());
}
}
결과
set의 크기 : 3
set2의 크기 : 3
5. Iterator : 데이터 분리
Iterator 인터페이스는 TreeSet이나 HashSet과 같이 입력하는 순서와 저장되는 순서가 달라서 get(), set()메서드를
사용할 수 없는 객체를 Iterator() 메서드를 사용해서 분리하며 하나의 객체를 가져오고 싶을 때도 사용한다.
HashSet데이터를 단순히 println으로 출력 하는 경우 [1, 2, 3], [a, b, c] 형태로 출력한다.
import java.util.HashSet;
import java.util.Iterator;
public class HashSetTest {
public static void main(String[] args) {
// Integer
HashSet<Integer> set = new HashSet<Integer>();
set.add(1);
set.add(2);
set.add(3);
set.add(1);
System.out.println("set의 값 : " + set);
// String
HashSet<String> set2 = new HashSet<String>();
set2.add("a");
set2.add("b");
set2.add("c");
set2.add("a");
System.out.println("set2의 값 : " + set2);
// Integer 출력
Iterator iter = set.iterator();
while(iter.hasNext()) {
System.out.print(iter.next() + " ");
}
System.out.println("");
// String 출력
Iterator iter2 = set2.iterator();
while(iter2.hasNext()) {
System.out.print(iter2.next() + " ");
}
}
}
결과
set의 값 : [1, 2, 3]
set2의 값 : [a, b, c]
1 2 3
a b c
더 자세한 내용은
[JAVA 기본/java2] - [java2] #17 - Collection Framework(Set/List/Map), Iterator
[java2] #17 - Collection Framework(Set/List/Map), Iterator
컬렉션 프레임 워크 컬렉션 프레임 워크란 데이터를 저장하는 클래스들을 표준화 한 설계이며 아래 그림과 같이 데이터를 저장하는 구조에 따라 3가지 인터페이스로 구성된다. Set, List, Map은 데
yoonddo.tistory.com
6. 검색하기
HashSet 내부의 원하는 값을 검색하는 경우 contains(value) 메서드를 사용한다.
값이 존재하면 true, 없다면 false를 리턴한다.
public class HashSetTest {
public static void main(String[] args) {
// Integer
HashSet<Integer> set = new HashSet<Integer>();
set.add(1);
set.add(2);
set.add(3);
set.add(1);
System.out.println("1은 있는가? : " + set.contains(1));
// String
HashSet<String> set2 = new HashSet<String>();
set2.add("a");
set2.add("b");
set2.add("c");
set2.add("a");
System.out.println("a는 있는가? : " + set2.contains("a"));
}
}
결과
1은 있는가? : true
a는 있는가? : true
출처: https://crazykim2.tistory.com/474 [차근차근 개발일기+일상:티스토리]