Java

HashSet

1space 2025. 6. 24. 03:35

자바의 정석[기초편]으로 공부한 내용을 정리한 글입니다.

 

HashSet의 기본 개념 및 Set 계층구조 이해

HashSet의 성질

  • 순서가 없음 (순서 X)
  • 중복 불가 (중복 X)
  • 즉, List와 반대로 "순서를 유지하지 않으면서 중복을 허용하지 않는" 컬렉션입니다.

계층 구조

  • HashSet은 Set 인터페이스를 구현한 대표적인 클래스입니다.
  • Set 인터페이스의 하위에는 SortedSet, 그 하위에는 TreeSet이 있고,
    • TreeSet: 정렬된 상태로 저장되는 Set
    • HashSet: 정렬도 안 되고 순서도 없음

순서를 유지하려면?

  • HashSet은 순서 없음.
    LinkedHashSet을 사용하면 입력한 순서를 유지할 수 있음

TreeSet은 정렬 기반

  • 값의 범위 검색 (from ~ to)이나 정렬된 데이터 유지가 필요할 때 유용

 

HashSet의 생성자와 주요 메서드

생성자 종류

  1. HashSet(): 기본 생성자
  2. HashSet(Collection c): 다른 컬렉션으로 초기화
  3. HashSet(int initialCapacity): 초기 용량 설정
  4. HashSet(int initialCapacity, float loadFactor): 초기 용량 + 로드 팩터 설정
    • loadFactor: 얼마나 채워졌을 때 내부 배열을 확장할 것인가 (예: 0.8 → 80% 차면 확장)

주요 메서드

  • 추가/삭제
    • add(Object o) / addAll(Collection c)
    • remove(Object o) / removeAll(Collection c)
    • retainAll(Collection c) : 교집합 유지
    • clear() : 전부 삭제
  • 조회/상태
    • isEmpty() : 비어 있는지
    • size() : 저장된 요소 수
    • contains(Object o) : 포함 여부
    • containsAll(Collection c) : 전부 포함 여부
  • 배열 변환
    • toArray() : 배열로 변환
    • toArray(Object[] a) : 지정 배열로 복사
  • 반복자
    • iterator() : Set의 요소를 하나씩 꺼낼 수 있는 Iterator 객체 반환

 

HashSet 사용 예제 – 중복 제거 & 출력

코드 설명

Object[] objArr = {"1", new Integer(1), "2", "2", "3", "3", "4", "4"};
Set set = new HashSet();
  • "1"(문자열)과 new Integer(1)(정수 객체)은 서로 다르다고 간주됩니다.
  • "2", "3", "4"는 문자열로서 중복되므로 한 번만 저장됩니다.
 
for(int i=0; i < objArr.length; i++) {
    set.add(objArr[i]);
}
  • 위 배열의 요소들을 하나씩 HashSet에 넣습니다.
  • HashSet이므로 중복은 자동 제거됩니다.
 
System.out.println(set);
  • HashSet 내부 요소를 직접 출력
  • 하지만 HashSet은 순서를 보장하지 않기 때문에, 출력 순서는 랜덤입니다.
 
Iterator it = set.iterator();
while(it.hasNext()) {
    System.out.println(it.next());
}
  • 반복자를 이용해 요소들을 하나씩 꺼내서 출력
1
1
2
3
4

 

HashSet → 정렬이 필요할 때 (List로 변환)

Set set = new HashSet();
while(set.size() < 6) {
    int num = (int)(Math.random()*45)+1;
    set.add(num);
}
  • 1~45 사이의 랜덤 숫자를 중복 없이 6개 저장
  • 중복이 자동 제거되므로, 6개가 될 때까지 반복
 
List list = new LinkedList(set);
  • HashSet → LinkedList로 복사
  • 이제 list는 정렬 가능한 리스트
 
Collections.sort(list);
System.out.println(list);
  • 리스트 정렬
  • 중복 없는 6개의 랜덤 숫자 → 정렬된 상태로 출력

 

요약

HashSet 순서 없음, 중복 제거, 빠른 검색
LinkedHashSet 순서 유지 + 중복 제거
TreeSet 자동 정렬 + 중복 제거
add() 요소 추가
iterator() 반복자 꺼내기
size() 저장된 개수
Collections.sort() List 정렬용 유틸리티
 

 

HashSet은 어떻게 중복을 판단하나요?

HashSet은 객체를 저장하기 전에 "이미 동일한 객체가 존재하는가?" 를 판단하여

  • 없으면 저장
  • 있으면 저장하지 않음

이 판단 기준이 바로 equals()와 hashCode() 메서드입니다.

 

HashSet에 저장되는 객체의 조건

equals()와 hashCode()를 왜 오버라이딩해야 하나요?

HashSet은 다음과 같이 동작합니다:

  1. 저장하려는 객체의 hashCode() 값을 먼저 계산합니다.
  2. 같은 해시코드가 있으면 → 그 객체들과 equals() 비교를 합니다.
  3. equals() 결과가 true면 → 중복된 객체로 판단하고 저장하지 않습니다.

따라서:

  • 두 객체가 같은 객체인지 판별하려면
    반드시 equals()와 hashCode()를 둘 다 오버라이딩해야 합니다.

 

예제

 
class Person {
    String name;
    int age;

    public boolean equals(Object obj) {
        if (!(obj instanceof Person)) return false;
        Person p = (Person) obj;
        return this.name.equals(p.name) && this.age == p.age;
    }

    public int hashCode() {
        return Objects.hash(name, age);
    }
}

이 코드에서 중요한 점:

  • equals: 이름과 나이가 모두 같아야 같은 객체로 간주합니다.
  • hashCode: Objects.hash(name, age) → name과 age가 같으면 동일한 hashCode를 반환합니다.

 

예시

HashSet set = new HashSet();

set.add("abc");
set.add("abc"); // 중복이라 저장 안됨

set.add(new Person("David", 10));
set.add(new Person("David", 10)); // 중복이라 저장 안됨

해설:

  • "abc"는 문자열이므로 equals()와 hashCode()가 이미 정의되어 있어서 동작 OK.
  • Person("David", 10)은 equals와 hashCode를 오버라이딩했기 때문에
    → 똑같은 이름과 나이의 Person은 중복으로 간주되어 두 번째 add는 무시됩니다.

 

만약 equals와 hashCode를 오버라이딩하지 않으면?

set.add(new Person("David", 10));
set.add(new Person("David", 10));
  • 위 두 줄은 다른 객체로 간주되어 둘 다 저장됩니다.
  • 이유: 기본 Object 클래스의 equals()는 주소(참조값) 비교를 하기 때문입니다.
    → 값은 같아도 다른 주소에 존재하므로 다르다고 판단합니다.

 

요약

HashSet 순서 없음, 중복 불가
중복 판단 기준 hashCode() → equals()
직접 만든 클래스 객체 저장 시 반드시 equals()와 hashCode()를 오버라이딩해야 중복 판단 가능
오버라이딩 기준 비교 기준이 되는 필드(예: name, age)를 이용해서 구현
 

'Java' 카테고리의 다른 글

HashMap  (0) 2025.06.24
TreeSet  (0) 2025.06.24
Comparator와 Comparable  (0) 2025.06.23
Arrays의 메서드  (0) 2025.06.23
Iterator, ListIterator, Enumeration  (0) 2025.06.23