Set - HashSet

코코·2020년 7월 30일
0

Java

목록 보기
14/25
post-custom-banner

HashSet

HashSet은 Set인터페이스를 구현한 가장 대표적인 컬렉션이다.

다시 상기하자면, Set은

  • 중복 허용 X
  • 순차 저장 X

중복된 데이터를 저장하려고 하면 false를 반환한다. HashSet의 특징을 이용하면 중복을 쉽게 제거할 수 있다.

HashSet의 메서드

method설명
HashSet()(생성자)객체 생성
HashSet(Collection c)지정한 컬렉션을 포함하는 객체 생성
HashSet(int initialCapacity)지정한 값을 초기용량으로 하는 객체 생성
HashSet(int initialCapacity, float loadFactor)초기 용량과 load factor를 지정하는 생성자
boolean add(Object o)객체 저장
boolean addAll(Collection c)지정한 컬렉션에 저장된 모든 객체 저장
void clear()모든 객체 삭제
Object clone()복제해서 반환(얕은 복사)
boolean contains(Object o)지정한 객체를 포함하고 있는지 알려준다.
boolean containsAll(Collection c)지정한 컬렉션에 저장된 모든 객체를 포함하고 있는지 알려준다.
boolean isEmpty()비어있는지 확인
Iterator iterartor()Iterator반환
boolean remove(Object o)지정한 객체 삭제
boolean removeAll(Collection c)지정한 컬렉션에 저장된 객체와 동일한 것을 모두 삭제
boolean retainAll(Collection c)지정한 컬렉션에 저장된 객체와 동일한 것만 남기고 모두 삭제
int size()객체의 개수 반환
Object[] toArray()지정한 객체를 객체 배열 형태로 반환
Object[] toArray(Object[] a)지정한 객체를 주어진 객체배열a에 담는다.

load factor는 저장공간이 가득 차기 전에 미리 용량을 확보하기 위한 것이다. 기본값은 0.75. 75% 채워지면 용량이 두 배로 늘어난다.

package com.javaex.ch11;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Bingo {
    public static void main(String[] args) {
        Set set = new HashSet();

        int[][] board = new int[5][5];

        for(int i = 0; set.size()<25;i++){
            set.add((int)(Math.random()*50)+1+"");
        }

        Iterator iterator = set.iterator();

        for(int i=0; i<board.length;i++){
            for(int j=0; j<board[i].length;j++) {
                board[i][j] = Integer.parseInt((String)iterator.next());
                System.out.print((board[i][j] < 10 ? "  ":" ")+board[i][j]);
            }
            System.out.println();
        }

    }
}

이 예제를 실행하면 같은 숫자가 비슷한 위치에 나온다는 사실을 발견할 수 있다. HashSet은 순서를 보장하지 않고 자체적인 저장방식에 따라 순서가 결정된다. 이런 경우 HashSet보다 LinkedHashSet을 쓰는 것이 더 나은 선택이다.

package com.javaex.ch11;

import java.util.HashSet;

public class HashSetEx3 {
    public static void main(String[] args) {
        HashSet set = new HashSet();

        set.add("abc");
        set.add("abc");

        set.add(new Person("coco", 20));
        set.add(new Person("coco", 20));

        System.out.println(set);
    }
}

class Person {
    String name;
    int age;

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

    @Override
    public String toString() {
        return name + " : " + age;
    }
}
/*
결과 : 
[abc, coco : 20, coco : 20]
*/

위 예제는 이름과 나이가 같으면 같은 사람으로 인식하려는 의도로 작성했다. 그러나 의도와 달리 결과는 두 개의 Person객체가 출력된다.

HashSet의 add()는 새로운 요소를 추가하기 전 기존 요소와 같은 것인지 판별하기 위해 추가하려는 요소의 equals()와 hashCode()를 호출하므로 두 메서드를 목적에 맞게 오버라이딩 할 필요가 있다.

package com.javaex.ch11;

import java.util.HashSet;

public class HashSetEx3 {
    public static void main(String[] args) {
        HashSet set = new HashSet();

        set.add(new Person("coco", 20));
        set.add(new Person("coco", 20));

        System.out.println(set);
    }
}

class Person {
    String name;
    int age;

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

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Person) {
            Person person = (Person)obj;
            return name.equals(person.name) && age == person.age;
        }
        return false;
    }

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

    @Override
    public String toString() {
        return name + " : " + age;
    }
}

hashCode()를 오버라이딩할 때 다음 세 가지 조건을 만족시켜야 한다.

  1. 실행 중인 애플리케이션 내 동일한 객체에 대해 여러 번 hashCode()를 호출해도 동일한 int값을 반환해야 한다. ( 실행할 때마다 동일한 값을 반환할 필요는 없다.)

  2. equals()를 이용해 true를 얻은 두 객체에 대해 각각 hashCode()를 호출해서 얻은 결과는 반드시 같아야 한다.

  3. equals()를 호출했을 때 false를 반환하는 두 객체는 hashCode() 호출에 대해 같은 int를 반환하는 경우가 있어도 괜찮다. 하지만 해싱hassing을 사용하는 컬렉션 성능을 향상시키기 위해서는 다른 int값을 반환하는 것이 좋다.

post-custom-banner

0개의 댓글