Vienna

Chapter 11) 컬렉션 프레임워크 - HashSet 본문

언어/Java의 정석

Chapter 11) 컬렉션 프레임워크 - HashSet

아는개발자 2023. 5. 7. 23:04

■ HashSet

  • Set 인터페이스를 구현한 가장 대표적인 컬렉션.
  • Set 인터페이스의 특징대로 중복된 요소를 저장하지 않는다.
  • 저장순서를 유지하지 않는다.
    • 만약 저장순서를 유지하고자 하는 경우에는 LinkedHashSet을 사용해야 한다.
import java.util.*;

public class Main {

    public static void main(String[] args) {
        Object[] objArr = {"1", new Integer(1), "2", "2", "3", "3", "4", "4", "4"};
        Set set = new HashSet();
        
        for(int i=0, iMax = objArr.length; i<iMax; i++){
            set.add(objArr[i]);
        }

        System.out.println("set = " + set);
    }
}

서로 다른 타입의 1은 다르다고 판단하는 것을 알 수 있다.

import java.util.*;

public class Main {

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

        for(int i=0; set.size()<6; i++){
            int num = (int)(Math.random()*45)+1;
            set.add(new Integer(num));
        }
        
        List list = new LinkedList(set);
        Collections.sort(list);
        System.out.println("list = " + list);
    }
}

import java.util.*;

public class Main {

    public static void main(String[] args) {
        Set set =new HashSet();
        //Set set = new LinkedHashSet();
        int[][] board = new int[5][5];

        for (int i = 0; set.size()<25; i++) {
            set.add((int)(Math.random()*50)+1);
        }
        Iterator it = set.iterator();
        for(int i=0; i< board.length; i++){
            for(int j=0; j< board[i].length; j++){
                board[i][j]=(Integer)it.next();
                System.out.print(String.format("%02d\t",board[i][j]));
            }
            System.out.println();
        }
    }
}

빙고판 만드는 예제.
책에서 나온대로 비슷한 위치에 비슷한 숫자가 계속 등장한다.
HashSet은 저장된 순서를 보장하지 않고 자체적인 저장방식에 따라 순서가 결정되기 때문.

즉, 이 경우에는 LinkedHashSet이 더 나은 선택이다.

 

import java.util.*;

public class Main {

    public static void main(String[] args) {
        Set set =new HashSet();
        
        set.add(new Person("David", 10));
        set.add(new Person("David", 10));

        System.out.println("set = " + set);
    }
}

class Person{
    String name;
    int age;

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

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

        return false;
    }

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

    public String toString(){
        return name+':'+age;
    }

}

이름과 나이가 일치하면 HashSet에 중복되게 들어가지 않도록 하는 코드 실행 결과.

HashSet의 add메서드는 새로운 요소를 추가하기 전에 기존에 저장된 요소와 같은 것인지 판별하기 위해 추가하려는 요소의 equals()와 hashCode() 함수를 호출하기 때문에 위와 같은 케이스에서 오버라이딩이 필요하다.

 

◇ 오버라이딩된 hashCode() 함수는 세 가지 조건을 만족해야 한다.

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