1. Set<E> 컬렉션의 특징
- 인덱스 정보를 포함하지 않은 동일한 타입의 묶음
- 집합의 개념과 같은 컬렉션
- Set<E>는 데이터를 구분할 수 있는 유일한 방법이 데이터 그 자체
- 동일한 데이터의 중복 저장을 허용하지 않음
- 데이터 중복 허용의 기준은 특정 데이터를 꺼낼 수 있느냐에 따라 달려있음
- List<E>
-> 중복된 데이터는 서로 다른 인덱스에 저장돼 있기 때문에 정확히 구분 가능
-Set<E>
-> 데이터가 중복됐을 때 aSet.get("다")가 가리키는 정확한 데이터를 알 수 없음
2. Set<E>의 주요 메서드
-contains(Object o)
-> 해당 Set<E> 매개변수로 넘어온 뎅이터가 객체 내의 포함돼 있는지를 불리언값으로 리턴
-iterator()
->Iterator<E>객체 리턴
->Set<E> 객체에서 데이터를 1개씩 꺼내는 기능 포함
->Set<E>은 인덱스가 없어 for문으로 데이터 못꺼냄
-Set<E>도 인터페이스 이므로 자바 컬렉션 프레임워크에서 제공하는 Set<E> 인터페이스를 상속한 구현 클래스 이용
(HashSet<E>, LinkedHashSet<E>, TreeSet<E>)
구분 | 메서드명 | 기능 |
데이터 추가 | add(E element) | 매개변수로 입력된 원소를 리스트에 추가 |
addAll(Collectiton<? Extends E> c) | 매개변수로 입력된 컬렉션 전체를 추가 | |
데이터 삭제 | remove(Object o) | 원소 중 매개변수 입력과 동일한 객체 삭제 |
clear() | 전체 원소 삭제 | |
데이터 정보 추출 | isEmpty() | Set<E> 객체가 비어 있는지 여부를 리턴 |
contains(Object o) | 매개변수로 입력된 원소가 있는지 여부를 리턴 | |
size() | 리스트 객체 내의 포함된 원소의 개수 | |
iterator() | Set<E> 객체 내의 데이터를 연속해 꺼내는 iterator 객체 리턴 | |
Set<E> 객체 배열 변환 | toArray() | 리스트를 Object 배열로 변환 |
toArray(T[] t) | 입력매개변수로 전달한 타입의 배열로 변환 |
1) 데이터 추가하기 - add()
- 중복된 데이터는 추가 x
- HashSet<E>은 모든 데이터를 하나의 주머니에 넣어 관리하므로 입력순서와 다르게 출력될 수도 있다.
Set<String> hSet1 = new HashSet<String>();
//1.add(E element)
hSet1.add("가");
hSet1.add("나");
hSet1.add("가");
System.out.println(hSet1.toString()); //[가,나]
//2.addAll(Collection<? extends E> c)
Set<String> hSet2 = new HashSet<String>();
hSet2.add("나");
hSet2.add("다");
hSet2.addAll(hSet1);
System.out.println(hSet2.toString()); //[가,다,나] //입력 순서와 다름
2) 데이터 삭제하기 -remove(), clear()
- Set<E>객체에는 인덱스 번호가 없으므로 데이터를 삭제하려면 remove() 메서드의 매개변수로 실제 삭제할 원솟값을 넣어야 함
//3.remove(Object o) hset2=[가,다,나]
hSet2.remove("나");
System.out.println(hset2.toString()); //[가,다]
//4.clear()
hset2.clear();
System.out.println(hset2.toString()); //[]
3) 데이터 정보 추출하기 -isEmpty(), contains(), iterator()
-isEmtpy()
-> 데이터가 비어 있는지의 여부
-contians(Object o)
->HashSet<E> 객체 안에 해당 원소가 있는지를 true/false로 리턴
-size()
-> 저장된 데이터의 개수를 정수형으로 리턴
- Iterator()
-> Set<E> 객체 내부의 데이터를 1개씩 꺼내 처리하고자 할때 사용
-> iterator() 메서드 호출시
- 제네릭 클래스 타입인 Iterator<E>의 객체 생성
(Iterator<String>iterator =hSet3.iterator();)
- hasNext()메서드는 다음으로 가리킬 원소의 존재 여부를 불리언으로 리턴
hasNext() = false이면 마지막 데이터까지 읽은것
hasNext() = true 이면 아직 읽을 데이터가 남아 있는것
- next() 메서드는 다음 원소 위치로 가서 읽은 값 리턴
cf> 최초 iterator<E>객체 생성시 객체가 가리키고 있는 위치는 첫 원소 바로 이전의 위칫값
첫 번째 원솟값을 읽으려면 iterator.next() 실행
while(iterator.hasNext()) {
System.out.println(iterator.next() +" "); } -> "아직 읽을 데이터가 남아있으면 다음 원소로 위치로 가서 읽은값을 리턴해라"
//5.isEmpty() hset2=[]
System.out.println(hset2.isEmpty()); //true
//6.contains(Object o)
Set<String>hSet3 = new HashSet<String>();
hSet3.add("가");
hSet3.add("다");
hSet3.add("나");
System.out.println(hSet3.contains("나"); //true
System.out.println(hSet3.contains("라"); //false
//7.size()
System.out.println(hset3.size()); //3
//8.iterator()
Iterator<String>iterator =hSet3.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next() +" "); //가 나 다
}
System.out.println();
-for-each 구문으로 데이터 정보 추출
//8.for-each
for(String s :hSet3) {
System.out.println(s+""); //가 다 나
}
System.out.println();
4) 배열로 변환하기 -toArray(), toArray(T[] t)
//9.toArray() hSet3 =[가 다 나]
Object() objArray = hSet3.toArray();
System.out.println(Arrays.toString(objArray)); //[가 다 나]
//10-1 toArray(T[] t) 배열 개수가 더 작을때
String[] strArray1 = hSet3.toArray(new String[0]);
System.out.println(Arrays.toString(strArray1)); //[가 다 나]
//10-2 toArray(T[] t) 배열 개수가 더 클때
String[] strArray2 = hSet3.toArray(new String[5]);
System.out.println(Arrays.toString(strArray2)); //[가 다 나 null null]
5) HashSet<E>의 중복 확인 메커니즘
-A a1 = new A(3) 과 A a2 = new A(3)
-> 3의 데이터를 넣으면 내부적으로는 new Integer(3)과 같이 객체로 변환돼 저장
-> 생성자에 동일한 값을 넘겨 객체를 생성했으므로 두 객체는 완벽히 똑같이 생김
-> But, 클래스 A에서 equals() , hashCode() 오버라이딩을 하지 않았으면 HashSet<E> 관점에선는 다른 객체
-String s1 = new String("안녕")과 String s2 =new String("안녕")
-> HashSet<E>의 관점에서 동일 객체
객체의 해시코드(HashCode)
- 객체가 저장된 번지와 같은 값
- 객체가 저장된 번지를 기준으로 생성된 정수형 고윳값
- hasCode() 메서드
-> object 클래스 정의 메서드
-> 객체의 해시코드값 리턴
- 오버라이딩하지 않았을 때 객체의 hashcode(), toString()를 이용한 해시코드값 출력
class A extends Object{}
public class Test{
public static void main(String[] args) {
A a = new A();
System.out.printf("%x", a.hashCode()); //7852e922
System.out.println(a.toString()); //패키지명.클래스명.@해시코드
}
}
-Objects.hash() 메서드를 이용한 해시코드 생성
-> 매개변수로 들어오는 값과 순서까지 고려해 고유한 해시코드 생성
System.out.println(Objects.hash(1,2,3)); //30817
System.out.println(Objects.hash(2,1,3)); //31747
System.out.println(Objects.hash("안녕")); //1611052
System.out.println(Objects.hash("방가")); //1537302
등가연산자(==)
- 스택 메모리값을 동등 비교
- 기본 자료형(int..)의 등가연산 -> 실제값 비교
- 참조 자료형(String..)의 등가연산 -> 위칫값 비교
equals() 메서드
- Obejct 클래스의 메서드
- 등가연산과 완벽하게 동일
- 자신의 객체와 매개변수로 넘어온 객체의 등가연산을 수행한 결과를 리턴
public boolean equals(Object obj) {
return (this ==obj);
}
-equals() 메서드를 오버라이딩하지 않았을 때 등가 연산과 equlas() 연산 결과 비교
->등가 연산과 equals() 메서드의 결과는 동일한 값
class A{
int data;
public A(int data) {
this.data =data;
}
}
public class Test {
public static void main(String[] args) {
A a1 = new A(3);
A a2 = new A(3);
System.out.println(a1 == a2); //false
System.out.println(a1.equals(a2)); //false
}
}
HashSet<E>에서의 중복 확인 메커니즘
1단계 hashCode()값이 동일한지 확인
2단계 equals() 결과가 true인지 확인
- 해시코드가 동일하고 equals()메서드가 true이면 두 객체는 동일한 객체로 인지(중복된 값으로 인식)
- 두 메서드 모두 오버라이딩 하지 않았을 때
-> 2개의 객체를 동일한 생성자로 생성했기 떄문에 객체의 모양은 동일하지만, 각각 다른 위치에 저장
-> HashSet<E>의 관점에서는 완벽히 다른 객체
class A {
int data;
public A(int data) {
this.data=data;
}
}
public class Test{
public static void main(String[] args) {
//equals():오버라이딩 x + hashCode(): 오버라이딩 x
Set<E> hashSet1 = new HashSet<>();
A a1 = new A(3);
A a2 = new A(3);
System.out.println(a1 == a2); //false
System.out.println(a1.equals(a2)); //false
System.out.println(a1.hashCode() + " " +a2.hashCode()); // 2018699554, 1311053135
hashSet1.add(a1);
hashSet1.add(a2);
System.out.println(hashSet1.size()); //2(다른객체)
}
}
- equals() 메서드만 오버라이딩 했을때
-> 오버라이딩한 equals() 메서드는 두 객체의 필드값 비교하므로 true 리턴
-> 해시코드값은 두 객체가 다르므로 서로 다른값 가짐
-> HashSet<E>의 관점에서는 완벽히 다른 객체
class B{
int data;
public B(int data) {
this.data =data;
}
//override
public boolean equals(Obeject obj) {
if(obj instance of B){
if(this.data == ((B)obj).data)
return true;
}
return false;
}
}
public class Test{
public static void main(String[] args) {
//equals() :오버라이딩o +hascode() : 오버라이딩 x
Set<B>hashSet2 = new HashSet<>();
B b1 = new B(3);
B b2 = new B(3);
System.out.println(b1 == b2); //false
Sysetm.out.println(b1.equals(b2)); //true
System.out.println(b1.hashCode() +" "+b2.hashCode()); //118352462, 1550089733
hashSet2.add(b1);
hashSet2.add(b2);
System.out.println(hashSet2.size()); //2(다른 객체)
}
}
-equals(), hashCode() 메서드 모두 오버라이딩했을 떄
-> equals()는 필드값이 동일할 때 true 리턴하도록 오버라이딩
-> hashCode()는 Objects 클래스의 정적 메서드인 hash() 메서드를 사용해 필드값 기준으로 해시코드 생성
-> return (new Integer(data)).hashCode() => return data로 간단히 쓰기 가능
class C{
int data;
public C(int data) {
this.data =data;
}
//override
public boolean equals(Object obj) {
if(obj instanceof C) {
if(this.data == ((c)obj.data)
return ture;
}
return false;
}
//override
public int hashCode() {
return Objects.hashcode(data); //data
}
}
public class Test {
public staic void main(String[] args) {
//equals() :오버라이딩 o, hashCode(): 오버라이딩 O
Set<C>hashSet3 = new HashSet<>();
C c1 = new C(3);
C c2 = new C(3);
System.out.println(c1 == c2); //false
System.out.pritnln(c1.equals(c2)); //true
System.out.println(c1.hashCode()+ " " +c2.hashCode()); //34 34
hashSet3.add(c1);
hashSet3.add(c2);
System.out.println(hashSet3.size()); //1(같은객체)
}
}
'Java > 문법' 카테고리의 다른 글
17 - 4 장 Map<K,V> 컬렉션 인터페이스 (0) | 2023.06.18 |
---|---|
17 - 3장 Set<E> 컬렉션 인터페이스 (2) (2) | 2023.06.18 |
17 - 2장 List<E> 컬렉션 인터페이스 (0) | 2023.06.16 |
17 - 1장 컬렉션 프레임워크 개념과 구조 (0) | 2023.06.16 |
16 - 5장 제네릭의 상속 (0) | 2023.06.16 |