본문 바로가기
Java의 정석/컬렉션 프레임워크

HashSet (2)

by Hwanii_ 2023. 10. 9.
728x90

ch11-37 ~ 38 HashSet (2)

 

11 - 37 HashSet - 예제

 

- HashSet 은 객체를 저장 하기 전에 기존에 같은 객체가 있는지를 확인 한다.

같은 객체가 없으면 저장 하고, 있으면 저장 하지 않는다.

 

- boolean add(Object o) 메서드는 저장할 객체의 equals() 메서드 와 hashCode() 메서드를 호출 한다.

 

즉, Set에 저장 할 때 add() 메서드를 사용 할텐데, 

이때 저장하는 객체를 위의 메서드를 자동 호출 해서 중복 되는 객체가 있는지 없는지를 확인 한다.

 

하지만, equals() 메서드와 hashCode() 메서드가 오버라이딩 되어 있어야 정상적으로 확인 할 수 있다.

 

그동안,

equals() 메서드만 오버라이딩 해서 사용 했었는데,

원래 정석으로는 equals() 메서드를 오버라이딩 한다면 hashCode() 메서드도 오버라이딩 하는게 정석 이다.

 

예제 03 )

 

class Ex11_11 {

    public static void main(String[] args) {

        HashSet set = new HashSet();

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

        set.add(new Person2("David", 10));
        set.add(new Person2("David", 10));    //	중복 인데 저장이 됬음. => equals(), hashCode() 오버라이딩 필요

        System.out.println(set);
    }
}

class Person2 {

    String name;
    int age;

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

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

 

[ console ]

 

 

set 컬렉션은 중복 값이 저장 되면 안되는데, 문자열 abc는 중복 이라서 확실 하게 중복 저장이 되지 않았다.

 

하지만,

Person2 타입 객체는 두번 저장 했는데, 중복 저장이 되어 버렸다.

 

당연히 이게 맞다. 원래 타입이 같은 두 객체는 "각각" new 가 되었으므로 다른 객체 이다.

 

하지만, 논리적으로 내부 멤버변수 == 프로퍼티 가 동일 하다면 같은 객체라고 취급 해줘야 하는 상황 일 때

 

클래스 내부에 equals() 메서드와 hashCode() 메서드를 재정의 하면 된다.

 

그래서 두 메서드를 재정의 해준다.

 

@Override
    public boolean equals(Object obj) {

        if (!(obj instanceof Person2)) {
            return false;
        }

        Person2 p2 = (Person2) obj;

        return this.name.equals(p2.name) && this.age == p2.age;
    }

    @Override
    public int hashCode() {

        //	Objects 클래스의 hash() 메서드를 사용. (가변 인자)
        //	매개변수로 멤버변수를 작성 한다. => 멤버변수가 모두 같으면 같은 객체 이기 때문. (객체를 구분 하는 기준이 멤버변수)

        return Objects.hash(name, age);
    }

 

[ console ]

 

 

그러면 중복 객체가 저장이 되지 않는 것을 확인 할 수 있다.

 

지금 상황에서는 생성자 내부 멤버변수가 David, 10 으로 동일 하니까 멤버변수를 기준으로 객체를 판단 하는 것이다.

 

>> add() 메서드를 사용 해서 set에 객체를 저장 하면 자동으로 equals() 와 hashCode() 메서드를 호출 !

 

 

 

예제 04 )

 

set 컬렉션에 값을 저장 하고, 교집합, 합집합, 차집합을 로직을 통해 구해보기

 

import java.util.*;

class Ex11_12 {

    public static void main(String args[]) {

        HashSet setA = new HashSet();
        HashSet setB = new HashSet();
        HashSet setHab = new HashSet();    //	합집합
        HashSet setKyo = new HashSet();    //	교집합
        HashSet setCha = new HashSet();    //	차집합

        setA.add("1");
        setA.add("2");
        setA.add("3");
        setA.add("4");
        setA.add("5");
        System.out.println("A = " + setA);

        setB.add("4");
        setB.add("5");
        setB.add("6");
        setB.add("7");
        setB.add("8");
        System.out.println("B = " + setB);

        Iterator it = setB.iterator();
        while (it.hasNext()) {    //	B를 하나씩 차례대로 돌면서 ~
            Object tmp = it.next();
            if (setA.contains(tmp))    //	6, 7, 8 은 contains() 메서드의 결과가 false
                setKyo.add(tmp);
        }

        it = setA.iterator();
        while (it.hasNext()) {    //	A를 하나씩 차례대로 돌면서 ~
            Object tmp = it.next();
            if (!setB.contains(tmp))    //	B 집합의 값과 A 집합의 값을 차례대로 비교 하면서 B 집합의 값이 A 집합의 값을 포함 하고 있지 않다면 ~
                setCha.add(tmp);    //	차집합에 A 집합의 값만 add() 하겠다는 말 ~
        }

        it = setA.iterator();
        while (it.hasNext())    //	A를 하나씩 차례대로 돌면서 조건 상관 없이 합집합에 모든 값을 add() ~
            setHab.add(it.next());

        it = setB.iterator();
        while (it.hasNext())    //	B를 하나씩 차례대로 돌면서 조건 상관 없이 합집합에 모든 값을 add() ~
            setHab.add(it.next());

        System.out.println("A ∩ B = " + setKyo);
        System.out.println("A U B = " + setHab);
        System.out.println("A - B = " + setCha);

    }

}

 

[ console ]

 

 

set 컬렉션의 값을 Iterator 인터페이스의 핵심 메서드인 hasNext() 와 next() 메서드를 사용 해서,

set 컬렉션의 값에 접근 하고,

값이 조건에 부합 하면 ( contains() 메서드를 사용 해서 ) 새로운 set 컬렉션에 값을 add() 한다.

 

근데 위와 같이 로직으로 어렵게 결과값을 구하지 않고 간단하게 메서드를 사용 해서 구할 수 있다.

 

 

retainAll()

addAll()

removeAll()

 

메서드를 사용 해서 쉽게 구할 수 있다.

 

 

주석 처리를 하고 setA 집합과 setB 집합의 교집합을 구하면 ~

 

 

이렇게 공통 되는 값인 4, 5 를 확인 할 수 있다.

 

 

합집합을 구하면 ~

 

 

차집합을 구하면 ~

 

 

 

이렇게 쉽게 구할 수 있게 된다.

반응형

'Java의 정석 > 컬렉션 프레임워크' 카테고리의 다른 글

TreeSet (2)  (1) 2023.10.09
TreeSet (1)  (0) 2023.10.09
HashSet (1)  (0) 2023.09.20
Comparator & Comparable  (0) 2023.09.20
Arrays 클래스  (0) 2023.09.20