고래씌
[JAVA] 14-2. 컬렉션(Collection) - Set 본문
1. Set - HashSet
=> 중복값을 허용하지 않음
=> 저장된 순서를 보장하지 않음
▶ 구현 클래스로 HashSet, LinkedHashSet, TreeSet이 있음
▶ LinkedHashSet : 중복을 허용하지 않는다. 단, 저장된 순서를 유지
▶ TreeSet : 중복을 허용하지 않는다. 단, 오름차순 정렬 지원
1) 크기 구하기 : size()
Set<String> hs1 = new HashSet<>(); // String 자료형만 들어갈 수 있음
// Set객체 내부로 값을 추가 : add(추가할 값)
hs1.add(new String("반갑습니다."));
hs1.add(new String("반갑습니다."));
hs1.add("여러분");
hs1.add("안녕하세요.");
hs1.add("안녕하세요.");
hs1.add("여러분");
System.out.println(hs1);
// 크기 구하기 : size()
System.out.println("hs1의 크기 : " + hs1.size());
☞ 중복값 저장되지 않은 것 확인
2) 값 삭제 : remove(삭제할 값)
hs1.remove("여러분");
System.out.println(hs1);
3) 모든 값 삭제 : clear()
hs1.clear();
System.out.println(hs1);
4) Student 클래스에 equals(), hashCode() 재정의
■ equals(), hashCode() 함수를 재정의하지 않은 Student 클래스
package com.kh.chap02_set.part01_hashSet.model.vo;
public class Student {
private String name;
private int age;
private int score;
public Student() {
}
public Student(String name, int age, int score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", score=" + score + "]";
}
}
import com.kh.chap02_set.part01_hashSet.model.vo.Student;
public class SetRun {
public static void main(String[] args) {
HashSet<Student> hs2 = new HashSet(); // new 객체로 생성된 Student 객체만 들어갈 수 있음
hs2.add(new Student("공유", 40, 100));
hs2.add(new Student("김갑생", 33, 30));
hs2.add(new Student("홍길동", 24, 70));
hs2.add(new Student("공유", 40, 100));
System.out.println(hs2);
☞ 동일한 값이 있지만 객체가 다 서로 다른 주소값으로 들어가서 set은 주소값으로만 봤을때 동일한 객체라고 판단X
☞ 저장순서 유지 X, 중복값 저장 O => 동일객체로 판단하지 않았기 때문.
☞ 값이 추가될 때 equals(), hashCode()로 이미 들어간 값중에 현재 추가하고자 하는 값이 존재하는지 먼저 확인하기 때문.
☞ 단, 위 두 메소드(equals, hashCode)를 override하지 않으면 Object 클래스의 equals와 hashCode함수를 기준으로 동일여부를 확인함.(주소값 간의 비교를 수행)
※ 정리
▶ HashSet에 객체를 담을 때 내부적으로 equals()로 비교 + hashCode()값이 일치하는지도 비교
equals()한 결과가 true이고, hashCode() 값이 일치하면 => 동일 객체로 판단(중복값 저장하지 않음)
▶ Object클래스의 equals() : 두 객체의 주소값을 가지고 비교해서 일치하면 true / 일치하지 않으면 false
▶ Object클래스의 hashCode() : 두 객체의 주소값을 기반으로 해시코드값을 만들어서 반환
▶ 객체의 필드값 기준으로 동일한 객체인지 여부를 판단하게 하려면 위 두 메소드를 오버라이딩 해줘야함.
■ Student 클래스에 equals(), hashCode() 재정의
① equals() (직접 작성)
@Override
public boolean equals(Object obj) {
// Student.equals(비교대상 Student 객체)
if(!(obj instanceof Student)) {
return false;
}
Student other = (Student) obj;
// 3가지 필드값이 모두 동일한 경우 동일한 객체로 판단할 예정
if(this.name.equals(other.name) && this.age == other.age && this.score == other.score)
return true;
return false;
}
☞ Student 클래스 필드에 선언된 name 과 age, score가 모두 일치하면 동일한 객체로 판단함
this.name.equals(other.name) && this.age == other.age && this.score == other.score
② hashCode() (직접 작성)
// 객체의 주소값이 아닌, 필드값을 기준으로 해시코드를 만들어서 반환하도록 정의
public int hashCode() {
return (name+age+score).hashCode(); // 3가지 필드를 가지고 hashcode를 만듦
}
우리는 Generate를 이용해 equals(), hashCode()를 재정의해주겠다!
package com.kh.chap02_set.part01_hashSet.model.vo;
public class Student {
private String name;
private int age;
private int score;
public Student() {
}
public Student(String name, int age, int score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", score=" + score + "]";
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (score != other.score)
return false;
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + score;
return result;
}
}
import com.kh.chap02_set.part01_hashSet.model.vo.Student;
public class SetRun {
public static void main(String[] args) {
HashSet<Student> hs2 = new HashSet();
hs2.add(new Student("공유", 40, 100));
hs2.add(new Student("김갑생", 33, 30));
hs2.add(new Student("홍길동", 24, 70));
hs2.add(new Student("공유", 40, 100));
System.out.println(hs2);
☞ 다시 실행한 결과, 중복값 "공유" 객체가 하나 삭제된 것을 확인
▶ Student 클래스에 equals() 오버라이딩 : 세 필드값이 모두 일치하면 true, 하나라도 다를 시 false 반환
▶ Student 클래스에 hashCode() 오버라이딩 : 세 필드값 기반으로 해시코드 값을 생성
5) Set의 반복문
※ Set → 데이터가 무작위로 저장되어 있음 => 즉, index 개념 無 => 기본반복문 활용할 수 없다!!!!!
■ Set내부에 담겨있는 데이터를 순차적으로 가져오고자 할 때?
방법 ① for문(향상된 for문만 사용 가능)
HashSet<Student> hs2 = new HashSet(); // new 객체로 생성된 Student 객체만 들어갈 수 있음
hs2.add(new Student("공유", 40, 100));
hs2.add(new Student("김갑생", 33, 30));
hs2.add(new Student("홍길동", 24, 70));
hs2.add(new Student("공유", 40, 100));
// ① for문 (향상된 for문만 사용 가능)
for(Student s : hs2) {
System.out.println(s);
}
방법 ② Set계열 클래스를 ArrayList클래스로 변환
HashSet<Student> hs2 = new HashSet(); // new 객체로 생성된 Student 객체만 들어갈 수 있음
hs2.add(new Student("공유", 40, 100));
hs2.add(new Student("김갑생", 33, 30));
hs2.add(new Student("홍길동", 24, 70));
hs2.add(new Student("공유", 40, 100));
// ② Set계열 클래스를 ArrayList클래스로 변환
// ArrayList<Student> list = new ArrayList(); // 비어있는 리스트 생성
// list.addAll(hs2); // 리스트에 hs2에 담겨있는 객체들을 모두 추가하는 방식
ArrayList<Student> list = new ArrayList<>(hs2); // hs2에 담겨있는 모든 객체들이 추가된 채로 리스트가 생성
for(int i=0; i<list.size(); i++) {
System.out.println(list.get(i));
}
방법 ③ Iterator
HashSet클래스에서 제공하는 iterator 반복자를 이용한 방법
HashSet<Student> hs2 = new HashSet(); // new 객체로 생성된 Student 객체만 들어갈 수 있음
hs2.add(new Student("공유", 40, 100));
hs2.add(new Student("김갑생", 33, 30));
hs2.add(new Student("홍길동", 24, 70));
hs2.add(new Student("공유", 40, 100));
// ③ Iterator
// HashSet클래스에서 제공하는 iterator 반복자를 이용한 방법
Iterator<Student> it = hs2.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
2. LinkedHashSet / TreeSet
▶ LinkedHashSet - 저장순서를 기록
▶ TreeSet - 값의 정렬을 지원
// LinkedHashSet
Set<Integer> set1 = new LinkedHashSet<>(); // 순서가 유지되는 Set
set1.add(34);
set1.add(25);
set1.add(100);
set1.add(1);
set1.add(134);
set1.add(44434);
System.out.println(set1);
// TreeSet //오름차순 정렬
Set<Integer> set2 = new TreeSet<>(set1);
System.out.println(set2); // comparTo 함수가 호출되어 자동으로 오름차순 정렬이 됨
☞ LinkedHashSet은 순서가 유지됨
☞ TreeSet은 Comprable 인터페이스가 구현되어 있으므로 오름차순으로 정렬되어 출력 되어 오름차순 정렬이 됨.
☞ Student 객체를 정렬할때는 Set<Student> set2 = new TreeSet<>();
☞ Student 클래스에 comparTo 메소드를 재정의하여 호출하면 됨
'JAVA > JAVA 기초' 카테고리의 다른 글
[JAVA] Set 실습 문제 - Lottery (0) | 2023.10.25 |
---|---|
[JAVA] 14-3. 컬렉션(Collection) - Map (0) | 2023.10.25 |
[JAVA] ArrayList - Music 실습 문제 (0) | 2023.10.24 |
[JAVA] 14-1. 컬렉션(Collection) - ArrayList (0) | 2023.10.24 |
[JAVA] 입출력(보조스트림) 실습문제 (0) | 2023.10.24 |