국비 18

냐아암·2023년 5월 11일
0

국비

목록 보기
24/114

Set(집합)

순서를 유지하지 않으며(인덱스 없음) 중복을 허용하지 않는다.(null도 중복X)

Set이 중복을 확인하는 방법
: 객체가 가지고 있는 값이 모두 같으면 중복으로 판단
-> 이때 필드값이 모두 같은지 비교하기 위해 객체에 equals()가 오버라이딩 되어있어야 함

  • Iterator: 객체 반복 접근자
    Iterator<String> it = set.iterator()
    변수명.hasNext()
    변수명.next()
    Iterator<String> it = set.iterator();
    	
    	//set.iterator(): Set을 Iterator가 하나씩 꺼내갈 수 있는 모양으로 변환해줌
    	
    	while(it.hasNext()) { //하나씩 꺼냈을 때 다음 값이 없는 경우 == 끝
    		//-> 다음 값이 있으면 반복해야 함
    		
    		//변수명.hasNext(): 다음 값이 있으면 true 반환
    		//변수명.next(): 다음 값(객체)를 얻어옴
    		
    		String temp = it.next();
    		System.out.println(temp);
    	}
  • 향상된 for문
    for(하나씩 꺼내서 저장할 변수 : 컬렉션) {}

  • 변수명.size(): 저장된 데이터 개수 반환
    set.size()

  • 변수명.remove(String e): Set에 저장된 객체 중 매개변수 e와 필드값이 같은 객체 제거 --> print 시 true, false 값 반환
    set.remove("라인")


HashSet

Set<String> set = new HashSet<String>();
Set의 대표적인 자식 클래스
Set에 객체를 저장할 때 hash함수를 사용하여 처리 속도가 빠름
동일 객체 뿐 아니라 동등 객체도 중복하여 저장하지 않음
- 사용조건 1: 저장되는 객체에 equals() 오버라이딩 필수
- 사용조건 2: 저장되는 객체에 hashCode() 오버라이딩 필수

  • 객체끼리 비교 시(Set X) 오버라이딩을 한 equals()를 사용할 때 객체 주소가 다르더라도 필드 값이 동일하면 true가 나옴
  • 객체 타입 Set 비교 시 eqauls()와 hashCode()를 오버라이딩 하면 객체 주소가 다르더라도 필드 값이 동일하면 같은 해시코드를 갖기 때문에 true가 나옴

-서로 다른 객체지만 필드 값이 같다 == 동등
-비교하려는 것이 정말 같은 하나의 객체이다 == 동일


LinkedHashSet

HashSet과 거의 동일하지만 Set에 추가되는 순서를 유지한다는 점이 다름


Wrapper클래스

기본 자료형 -> 객체로 포장하는 클래스
컬렉션에 기본 자료형 값을 저장할 때 사용

**static 방식으로 wrapper 클래스 사용
"int 최솟값: " + Integer.MIN_VALUE
"double 최솟값: " + Double.MIN_VALUE

- Autoboxing(자동 포장)
Integer w2 = 100;
Integer w3 = 100;
(Integer) (int -> Integer) 자동 포장

  • AutoUnboxing(자동 포장 해제): 자동 포장된 것을 연산할 때 다시 포장을 자동으로 벗겨냄
    "w2 + w3
    Integer + Integer -> int + int (자동 포장 해제)

cf. parsing: 데이터의 형식을 변환
Integer.parseInt("100");

Member

package edu.kh.collection.model.vo;

import java.util.Objects;

public class Member {
	
	private String id;
	private String pw;
	private int age;
	
	public Member() {}

	public Member(String id, String pw, int age) {
		super();
		this.id = id;
		this.pw = pw;
		this.age = age;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPw() {
		return pw;
	}

	public void setPw(String pw) {
		this.pw = pw;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Member [id=" + id + ", pw=" + pw + ", age=" + age + "]";
	}

	
	//hashCode() , equals() 단축키 alt shift S
	/*
	@Override
	public int hashCode() {
		return Objects.hash(age, id, pw);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Member other = (Member) obj;
		return age == other.age && Objects.equals(id, other.id) && Objects.equals(pw, other.pw);
	}
	*/
	
	
	
	
	//Object.equals() 오버라이딩
	//-현재 객체와 매개변수로 전달받은 객체의 필드가 같은지 비교하는 형태로 오버라이딩
	@Override
	public boolean equals(Object obj) {
		
		//매개변수를 다운 캐스팅 해야 함
		//다운 캐스팅을 통해 부모 참조변수가 자식 객체를 참조
		Member other = (Member)obj;
		
		//필드 값 비교
		return this.id.equals(other.id) && this.pw.equals(other.pw) && this.age == other.age;
				//this 빼도 됨
		
		
	}
	
	//Object.hashCode() 오버라이딩
	@Override
	public int hashCode() {
		//필드 값이 같은 객체는 같은 정수를 반환해야 한다.
		// == 필드 값을 이용해서 정수를 만들면 된다.
		
		final int PRIME = 31; //31이 연산속도가 빠른 소수 중 하나
				//소수
		
		int result = 1; //결과 저장용 변수
		
		result = result * PRIME * age;
		
		result = result * PRIME * (id == null ? 0 : id.hashCode());
		
		result = result * PRIME * (pw == null ? 0 : pw.hashCode());
		
		return result;
		
	}
	

}

SetService

package edu.kh.collection.model.service;

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

import edu.kh.collection.model.vo.Member;

public class SetService {
	
	//Set(집합)
	// - 순서를 유지하지 않음 ( == 인덱스 없음)
	// - 중복을 허용하지 않는다. (+ null도 중복X,  1개만 저장 가능)
	
	//***Set이 중복을 확인하는 방법***
	//-> 객체가 가지고 있는 필드 값이 모두 같으면 줃복으로 판단
	//-->이때 필드 값이 모두 같은지 비교하기 위해
	//	 객테에 "equals()"가 반드시 오버라이딩 되어있어야 한다.
	
	public void ex1() {
		
		Set<String> set = new HashSet<String>();
		
		//HashSet: Set의 대표적인 자식 클래스
		//사용조건 1: 저장되는 객체에 equals() 오버라이딩 필수
		//사용조건 2: 저장되는 객체에 hashCode() 오버라이딩 필수
		
		// *참고: Hash라는 단어가 붙은 컬렉션은
		//		 반드시 저장되는 객체에 equals(), hashCode()를 오버라이딩 해야 함
		
		//Set.add(String e): 추가 //타입 제한 안 할 시 Object 타입
		set.add("네이버");
		set.add("카카오");
		set.add("라인");
		set.add("쿠팡");
		set.add("배달의 민족");
		set.add("배달의 민족");
		set.add("배달의 민족");
		set.add(null);
		set.add(null);
		set.add(null);
		
		System.out.println(set);
		//확인할 것: 1. 순서 / 2. 중복X / 3. null 중복X 
		//[null, 배달의 민족, 카카오, 네이버, 쿠팡, 라인]
		
		//size(): 저장된 데이터의 개수 반환
		System.out.println("저장된 데이터의 수: "+ set.size()); 
		//저장된 데이터의 수: 6
		
		//remove(String e): Set에 저장된 객체 중 매개변수 e와 필드값이 같은 객체 제거
		//					+) Hash라는 단어가 포함된 Set이면 hashCode()도 같아야 함
		
		System.out.println(set.remove("라인")); //true
		System.out.println(set.remove("야놀자")); //false
		
		System.out.println(set); //[null, 배달의 민족, 카카오, 네이버, 쿠팡]
		
		//set은 순서가 없어서 저장된 객체 하나를 얻어올 수 있는 방법이 없다.
		//-> 대신에 Set 전체의 데이터를 하나씩 반복적으로 얻어올 수는 있다.
		
		
		//1. Iterator(반복자)
		//	-컬렉션에서 제공하는 컬렉션 객체 반복 접근자
		//	(컬렉션에 저장된 데이터를 임의로 하나씩 반복적으로 꺼내는 역할)
		
		//Iterator가 얻어온 데이터의 타입은 모두 String임을 알려줌
		Iterator<String> it = set.iterator();
		
		//set.iterator(): Set을 Iterator가 하나씩 꺼내갈 수 있는 모양으로 변환해줌
		
		while(it.hasNext()) { //하나씩 꺼냈을 때 다음 값이 없는 경우 == 끝
			//-> 다음 값이 있으면 반복해야 함
			
			//변수명.hasNext(): 다음 값이 있으면 true 반환
			//변수명.next(): 다음 값(객체)를 얻어옴
			
			String temp = it.next();
			System.out.println(temp);
		}
		
		
		System.out.println("============================================");
		
		//2. 향상된 for문 사용
		//	 for(하나씩 꺼내서 저장할 변수 : 컬렉션)
		for( String temp : set ) {
			System.out.println(temp);
		}
		
		
	}
	
	public void ex2() {
		//Object의 equals(), hashCode() 오버라이딩
		
		//A.equals(B): A와 B가 가지고 있는 필드 값이 같으면 true, 아니면 false
		
		//Hash 함수: 입력된 단어를 지정된 길이의 문자열로 변환하는 함수(중복X)
		//ex) 입력: 111 "asdfg" (5글자)
		//ex) 입력: 1234567 "qwert" (5글자)
		
		//hashCode(): 필드 값이 다르면 중복되지 않는 숫자를 만드는 메소드
		
		// -> 왜 만들까? 빠른 데이터 검색을 위해(객체가 어디에 있는지 빨리 찾기 위해)
		
		//HashSet(): 중복 없이 데이터를 저장(Set)하고 데이터 검색이 빠름(hash)
		
		Member mem1 = new Member("user01", "pass01", 30);
		Member mem2 = new Member("user01", "pass01", 30);
		Member mem3 = new Member("user02", "pass02", 20);
		
		// mem1과 mem2가 같은지 비교
		System.out.println(mem1 == mem2); //주소 비교 --> false
										  //얕은 복사 제외하면 다 false값 나옴
		
		// mem1과 mem2가 가지고 있는 필드 값이 같은지를 비교
		if(mem1.getId().equals(mem2.getId()) ) { //아이디가 같을 경우
			if(mem1.getPw().equals(mem2.getPw())) { //비밀번호도 같을 경우
				if(mem1.getAge() == mem2.getAge()) { //나이까지도 같을 경우
					System.out.println("같은 객체입니다. (true)");
				}
			}
		}
		
		//-> 매번 비교하기 번거로움 -> 비교 코드 작성해서 재활용
		//						 == equals() 메소드 오버라이딩
		
		System.out.println("===============================================");
		
		System.out.println(mem1.equals(mem2)); //mem1과 mem2 필드 같은가? true
		System.out.println(mem1.equals(mem3)); //mem1과 mem3 필드 같은가? false
		
		//서로 다른 객체지만 필드 값이 같다 == 동등
		//비교하려는 것이 정말 같은 하나의 객체이다 == 동일
	}
	
	public void ex3() {
		
		//equals() 가 오버라이딩된 Member를 Set에 저장
		
		//[Key Point]: 중복이 제거가 되는가?
		
		Set<Member> memberSet = new HashSet<Member>();
		
		memberSet.add(new Member("user01", "pass01", 30));
		memberSet.add(new Member("user02", "pass02", 40));
		memberSet.add(new Member("user03", "pass03", 20));
		memberSet.add(new Member("user04", "pass04", 25));
		memberSet.add(new Member("user04", "pass04", 25));
		
		for(Member mem : memberSet) { //hashCode() 오버라이딩 전에는
			System.out.println(mem);  //객체 주소값이 다 다르기 때문에 필드값 같아도 다 출력
		}
		
		//hashCode() 오버라이딩 전
		// -> equals()가 오버라이딩 되어있지만 중복 제거가 되지 않음
		// -> 왜? HashSet은 hashCode()도 오버라이딩 해야 한다.
		
		Member mem1 = new Member("user01", "pass01", 30);
		Member mem2 = new Member("user01", "pass01", 30);
		Member mem3 = new Member("user01", "pass01", 31);
		
		System.out.println(mem1.hashCode());
		System.out.println(mem2.hashCode());
		System.out.println(mem3.hashCode());
		
	}
	
	public void ex4() {
		//Wrapper클래스: 기본 자료형 -> 객체로 포장하는 클래스
		
		//- 컬렉션에 기본 자료형 값을 저장할 때 사용
		//- 기본 자료형에 없던 추가 기능, 값을 이용하고 싶을 때 사용
		
		//<Wrapper 클래스 종류>
		//int		-> Integer
		//double 	-> Double
		//Boolean, Byte, Short, Long, Float, Character
		
		int iNum = 10;
		double dNum = 3.14;
		
		//기본 자료형 -> 포장
		Integer w1 = new Integer(iNum); // int가 Integer로 포장
		Double w2 = new Double(dNum); 
		
		//Wrapper 클래스 활용
		System.out.println("int 최댓값: " + w1.MAX_VALUE);
		System.out.println("double 최솟값: " + w1.MIN_VALUE);
											//기울어진 글씨 == static
											//static은 클래스명.필드명 / 클래스명.메소드명() 호출
		
		System.out.println("w1값: " + w1);
		System.out.println("w2값: " + w2);
		
		System.out.println("==========================================");
		
		System.out.println("static 방식으로 Wrapper 클래스 사용하기");
		
		System.out.println("int 최솟값: " + Integer.MIN_VALUE);
		System.out.println("double 최댓값: " + Double.MAX_VALUE);
		
		//*******************************************************
		//parsing: 데이터의 형식을 변환
		
		
		// !String 데이터를 기본 자료형으로 변환!
		int num1 =Integer.parseInt("100"); //문자열 "100"을 int 형식으로 변환
		double num2 = Double.parseDouble("1.23456"); //문자열 1.23456을 double로 변환
		
		System.out.println(num1 + num2); //101.23456
		//*******************************************************
	}
	
	public void ex5() {
		
		//Wrapper 클래스에 AutoBoxing / AutoUnboxing
		
		Integer w1 = new Integer(100);
		// 삭제선 == deprecated == 해당 구문은 삭제될 예정이다
		// ==> 사용을 권장하지 않는다.
		
		Integer w3 = 100;
		Integer w2 = 100;
	// (Integer)	(int -> Integer) 자동 포장
					//AutoBoxing
		
		// w2와 100은 원래 연산이 안 되어야 하지만
		// Integer는 int의 포장 형식이라는 것을 자바가 인식하고 있어서
		// 이와 같은 경우 int를 Integer로 자동 포장해준다.
		
		System.out.println("w2 + w3 = " + (w2 + w3)); //200
		// w2(Integer객체)
		// w3(Integer객체)
		// w2 + w3 == 객체 + 객체 --> 원래는 불가능
		
		// 하지만 Integer는 int의 포장형태라는 걸 Java가 인식하고 있어어
		// + 연산 시 포장을 자동으로 벗겨냄
		
		//Integer + Integer -> int + int (자동 포장 해제)
							// AutoUnboxing
		
	}
	
	public void lotto() {
		
		//로또 번호 생성기 version.2
//		Set<int> lotto = new HashSet<int>();
		//int로 타입 제한 불가능
		//-> 객체로만 저장하는 컬렉션에 기본 자료형 int를 넣을 수 없음
		
		//-> 해결방법: Wrapper 클래스를 이용해 기본 자료형을 객체로 포장
		
//		Set<Integer> lotto = new HashSet<Integer>(); //무작위 출력
//		Set<Integer> lotto = new LinkedHashSet<Integer>(); //실행 순서대로 출력
		Set<Integer> lotto = new TreeSet<Integer>(); //오름차순으로 출력
		
		//Integer는 equals(), hashCode() 오버라이딩 완료 상태
		
		while(lotto.size() < 6){
			//lotto에 저장된 값이 개수가 6개 미만이면 반복
			int random = (int)(Math.random()*45 + 1); // 1~45 사이 난수
			
			System.out.println(random);
			
			lotto.add(random); 
			//int값이 자동으로 Integer로 포장(AutoBoxing)되어 lotto에 추가
			
		}
		
		
		System.out.println("로또 번호: " + lotto);
		
	}

}

SetRun

package edu.kh.collection.run;

import edu.kh.collection.model.service.SetService;

public class SetRun {

	public static void main(String[] args) {

		SetService service = new SetService();
		
//		service.ex1();
//		service.ex2();
//		service.ex3();
//		service.ex4();
//		service.ex5();
		service.lotto();
	}

}
profile
개발 일지

0개의 댓글