[Java] 컬렉션 프레임워크_Set 컬렉션

Devlog·2024년 4월 3일

Java

목록 보기
39/41

✔️ Set 컬렉션

: List 컬렉션은 객체의 저장 순서를 유지할 수 있지만
Set 컬렉션은 저장 순서가 유지되지 않음
그리고 객체를 중복해서 저장할 수 없고,
하나의 null만 저장할 수 있음

: Set 컬렉션은
  = 수학의 집합과 비슷함
  → 집합은 순서와 상관없고 중복이 허용되지 않기 때문

   = 구슬 주머니와도 같음
  → 동일한 구슬을 2개 넣을 수 없고,
    들어갈(저장할) 때의 순서와
    나올(찾을) 때의 순서가 다를 수도 있기 때문

: Set 컬렉션에는 HashSet, LinkedHashSet, TreeSet 등이 있음

- Set 인터페이스의 메소드

: 인덱스로 관리하지 않기 때문에 인덱스를 매개값으로 갖는 메소드가 없음

: 메소드의 매개 변수 타입과 리턴 타입에 E라는 타입 파라미터가 있는데,
이것은 저장되는 객체의 타입을 Set 컬렉션을 생성할 때 결정하라는 뜻

ex)
Set컬렉션에 String 객체를 저장하고 삭제하는 방법

Set<String> set = ···;
set.add("홍길동");		// 객체 추가
set.add("홍길동2");	
set.remove("홍길동");	// 객체 삭제

→ Set<String>으로 set 변수를 선언함
이것은 Set 컬렉션에 저장되는 객체를 String으로 하겠단 의미

따라서 E 타입 파라미터는 String 타입이 되는 것임

그래서 add() 메소드와 remove() 메소드의 매개값은 문자열이 됨

: Set 컬렉션은 인덱스로 객체를 검색해서 가져오는 메소드가 없음

대신, 전체 객체를 대상으로 한 번씩 반복해서 가져오는 반복자(Iterator)를 제공

반복자는 Iterator 인터페이스를 구현한 객체를 말하는데,
iterator() 메소드를 호출하면 얻을 수 있음

Set<String> set = ···;
Iterator<String> iterator = set.iterator();

: Iterator<String> 타입의 iterator 변수에 대입한 이유는
반복해서 가져올 객체가 String 타입이기 때문임

- Iterator 인터페이스에 선언된 메소드

· next() , hasNext()
: 하나의 객체를 가져올 때는 next() 메소드를 사용
: 메소드를 사용하기 전에 먼저 가져올 객체가 있는지 확인하는 것이 좋음

: hasNext() 메소드는
가져올 객체가 있으면 true를 리턴하고
더이상 가져올 객체가 없으면 false를 리턴

따라서 true가 리턴하고
더 이상 가져올 객체가 없으면 false를 리턴함
따라서 true가 리턴될 때 next() 메소드를 사용해야함

- Set 컬렉션에서 String 객체들을 반복해서 하나씩 가져오는 코드

Set<String> set = ···;
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()) {
	//String 객체 하나를 가져옴
	String str = iterator.next();
}

- Iterator를 사용하지 않더라도 향상된 for문을 이용해서
전체 객체를 대상으로 반복할 수 있음

Set<String> set = ···;
for(String str : set) {
}

: Set 컬렉션에서 Iterator의 next() 메소드로
가져온 객체를 제거하고 싶다면 remove()메소드를 호출하면 됨

Iterator의 메소드이지만, 실제 Set 컬렉션에서 객체가 제거됨을 알아야함

- Set 컬렉션에서 "홍길동"을 제거하기

while(iterator.hasNext()) {
	String str = iterator.next();
	if(str.equals("홍길동")) {
		iterator.remove();
	}
}

✔️ HashSet

: Set 인터페이스의 구현 클래스임

Set<E> set = new HashSet<E>();

: 타입 파라미터 E에는 컬렉션에 저장할 객체 타입을 지정하면 됨

- String 객체를 저장하는 HashSet 생성하기

Set<String> set = new HashSet<String>();
Set<String> set = new HashSet<>();

: HashSet은 객체들을 순서 없이 저장하고 동일한 객체는 중복 저장하지 않음

: HashSet이 판단하는 동일한 객체란 꼭 같은 인스턴스를 뜻하지는 않음

: HashSet은 객체를 저장하기 전에
먼저 객체의 hashCode() 메소드를 호출해서 해시코드를 얻어내고,
이미 저장되어 있는 객체들의 해시코드와 비교함

만약 동일한 해시코드가 있다면 다시 equals() 메소드로
두 객체를 비교해서 true가 나오면 동일한 객체로 판단하고 중복 저장을 하지 않음

: 문자열을 HashSet에 저장할 경우에
같은 문자열을 갖는 String 객체는 동등한 객체로 간주되고
다른 문자열을 갖는 String 객체는 다른 객체로 간주됨

그 이유는 String 클래스가 hashCode()와 equals() 메소드를
재정의해서 같은 문자열일 경우
hashCode()의 리턴값은 같게,
equals()의 리턴값은 true가 나오도록 했기 때문임

👩‍💻 String 객체를 중복 없이 저장하는 HashSet

import java.util.*;

public class HashSetExample {
	public static void main(String[] args) {
		Set<String> set = new HashSet<String>();
		
		// "Java"는 한번만 저장됨
		set.add("Java");
		set.add("JDBC");
		set.add("Servlet/JSP");
		set.add("Java");
		set.add("iBATIS");
		
		// 저장된 객체 수 얻기
		int size = set.size();
		System.out.println("총 객체수: " + size);
		
		// 반복자 얻기
		Iterator<String> iterator = set.iterator();
		while(iterator.hasNext()) {
			// 1개의 객체를 가져옴
			String element = iterator.next();
			System.out.println("\t" + element);
		}
		
		// 1개의 객체 삭제
		set.remove("JDBC");
		set.remove("iBATIS");
		
		System.out.println("총 객체수: " + set.size());
		
		// 반복자 얻기
		iterator = set.iterator();
		for(String element : set) {
			System.out.println("\t" + element);
		}
		
		// 모든 객체를 제거하고 비움
		set.clear();
		if(set.isEmpty()) {
			System.out.println("비어 있음");
		}
	}
}

💻 결과
총 객체수: 4
	Java
	JDBC
	Servlet/JSP
	iBATIS
총 객체수: 2
	Java
	Servlet/JSP
비어 있음
👩‍💻
import java.util.*;

// hashCode()와 equals()메소드 재정의
class Member {
	public String name;
	public int age;
	
	public Member(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Member) {
			Member member = (Member) obj;
			return member.name.equals(name) && (member.age == age);
		} else {
			return false;
		}
	}
	
	@Override
	// name과 age 값이 같으면 동일한 hashCode를 리턴
	public int hashCode() {
		// name.hashCode()
		// String의 hashCode() 이용
		return name.hashCode() + age;
	}
}

// Member 객체를 중복 없이 저장하는 HashSet
public class HashSetExample2 {
	public static void main(String[] args) {
		Set<Member> set = new HashSet<Member>();
		
		// 인스턴스는 다르지만 내부 데이터가
		// 동일하므로 객체 1개만 저장
		set.add(new Member("홍길동", 30));
		set.add(new Member("홍길동", 30));
		
		System.out.println("총 객체수: " + set.size());
	}
}

💻 결과
총 객체수: 1

0개의 댓글