Set(집합)
순서를 유지하지 않으며(인덱스 없음) 중복을 허용하지 않는다.(null도 중복X)
Set이 중복을 확인하는 방법
: 객체가 가지고 있는 값이 모두 같으면 중복으로 판단
-> 이때 필드값이 모두 같은지 비교하기 위해 객체에 equals()가 오버라이딩 되어있어야 함
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(하나씩 꺼내서 저장할 변수 : 컬렉션) {}
변수명.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() 오버라이딩 필수
-서로 다른 객체지만 필드 값이 같다 == 동등
-비교하려는 것이 정말 같은 하나의 객체이다 == 동일
LinkedHashSet
HashSet과 거의 동일하지만 Set에 추가되는 순서를 유지한다는 점이 다름
Wrapper클래스
기본 자료형 -> 객체로 포장하는 클래스
컬렉션에 기본 자료형 값을 저장할 때 사용
**static 방식으로 wrapper 클래스 사용
"int 최솟값: " + Integer.MIN_VALUE
"double 최솟값: " + Double.MIN_VALUE
- Autoboxing(자동 포장)
Integer w2 = 100;
Integer w3 = 100;
(Integer) (int -> Integer) 자동 포장
"w2 + w3
Integer + Integer -> int + int (자동 포장 해제)
cf. parsing: 데이터의 형식을 변환
Integer.parseInt("100");
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;
}
}
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);
}
}
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();
}
}