1. Collection Framework
- 컬렉션 프레임워크
- 컬렉션을 다루기 위한 표준화된 프로그래밍 방식
- 컬렉션 = 객체
1.1. 컬렉션 프레임워크 사용 이유
- 배열
- 정적배열
- 전통적으로 프로그래밍에서 많은 양의 자료(데이터) 처리를 위해서는 배열을 이용
- 배열의 단점
- 배열에 담는 자료형은 동일해야 한다. 다른 자료형도 함께 넣지 못함
- 배열은 데이터의 크기를 알 수 없는 경우에는 부적합하다.
- 데이터의 크기가 미리 안정해진 경우, 파악하기 어려운 경우 배열 생성이 힘들다
- 기준을 많이 잡아놓고 다 사용하지 않는다면 메모리만 차지
- 기준을 낮게 잡아놓으면 기준치초과시 다시 생성해야 함
- 데이터의 크기가 미리 안정해진 경우, 파악하기 어려운 경우 배열 생성이 힘들다
- 컬렉션 프레임워크
- 동적배열
- 객체만 받음 - 오토박싱을 통한 자료형을 객체로 변환 후 받을 수 있다.
- 배열의 단점을 보완하기 위한 프레임워크
- 사용자의 사용여부에 따라 늘어나기도 줄어들기도 하는 배열
2. 컬렉션 프레임워크 핵심
- 용어
- Collection Framework: 아래 상속계층도 전체 묶음
- Collection class: Collection framework에 속하는 인터페이스를 구현한 class
- Collection: Collection Framework의 인터페이스 중 하나
- Collections: Collection Framework type의 객체에게 유용한 staticMethod를 제공하는 클래스
Arrays, Objects 같은 것
- Collection Framework: 아래 상속계층도 전체 묶음
- interface
- Iterable
- Collection
- List
- Set
- Map
- Collection
- Iterable
List, Set, Map 3가지가 핵심
인터페이스 | 특징 |
List | 순서 O, 중복 O |
Set | 순서 X, 중복 X |
Map | 순서 X, key - 중복 X value - 중복 O |
3. 핵심 인터페이스 method
- Collection, List, Set, Map
3.1. Collection 인터페이스
- 매개변수
- Object o : array, Object==class instance, Collection 타입 다 포함
- Collection c : Collection type만 포함
- Collection 인터페이스의 method는 list, set 이 상속
// 지정된 객체(o) 또는 Collection(c)의 객체들을 Collction에 추가
boolean add(Object o);
boolean addAll(Collection c);
void clear(); // Collection의 모든 객체를 삭제
// 지정된 객체(o) 또는 Collection의 객체들
boolean contains(Object o);
boolean containsAll(Collection c);
boolean equals(Object o); // 동일한 Collection인지 비교
int hashCode(); // Collection의 hash code를 반환
boolean isEmpty(); // Collection이 비어있는지 확인
Iterator iterator(); // Collection의 Iterator를 얻어서 반환
// 제거된 부분 존재시 true, 없을 시 false 반환
boolean remove(Object o); // 지정된 객체를 삭제
boolean removeAll(Collection c); // 지정된 Collection에 포함된 객체들을 삭제
boolean retainAll(Collection c); // (헷갈림 주의) Collection c 내부에 존재하는 객체가 retainAll을 하는 Collection에 존재시 해당 객체만 남기고 나머진 전부 제거
int size(); // Collection에 저장된 객체개수 반환
Object[] toArray(); // 컬렉션에 저장된 객체를 객체배열로 반환
Object[] toArray(Object[] a) // 지정된 배열에 Collection의 객체를 저장해서 반환
3.2. List 인터페이스
- List의 구현 클래스 중 핵심 class
- ArrayList
- LinkedList
// 지정된 위치에 객체 또는 컬렉션에 포함된 객체들을 추가한다.
void add(int index, Object element);
boolean addAll(int index, Collection c);
Object get(int index); // 지정된 index의 객체를 반환
int indexOf(Object o); // 지정된 객체의 index를 반환(순방향으로 찾음)
int lastIndexOf(Object o); // 지정된 객체의 index를 반환 (역방향으로 찾음)
// List의 객체에 접근할 수 있는 ListIterator를 반환한다.
ListIterator listIterator();
ListIterator listIterator(int index); // index 부터 시작
Object remove(int index); // 지정된 index에 있는 객체를 삭제하고 삭제된 객체를 반환
Object set(int index, Object element); // 지정된 index에 객체를 저장
void sort(Comparator c); // 지정된 비교자로 List 정렬
List subList(int fromIndex, int tolndex); // from~to까지 index의 객체 반환
3.3. Set 인터페이스
- Set의 구현 클래스 중 핵심 class
- HashSet
- TreeSet
- Set 인터페이스의 method는 모두 2.1. Collection 인터페이스로 부터 상속받은 것들이다.
3.4. Map 인터페이스
- Map의 구현 클래스 중 핵심 class
- HashMap
- TreeMap == TreeSet과 같은 특성을 가진다.
- 중요
- keySet(): 중복을 허용하지 않기 때문에 Set type으로 반환
- Values(): 중복을 허용하기 때문에 Collection type으로 반환
void clear(); // Map의 모든 객체를 삭제
boolean equals(Object o); // 동일한 Map인지 비교
int hashCode(); // 해시코드 반환
boolean isEmpty(); // Map이 비었는지 확인
int size(); // Map에 저장된 key-value쌍의 개수를 반환
boolean containsKey(Object key); // 지정된 key 객체와 일치하는 Map의 key객체가 있는지 확인
booelan containsValue(Object value); // 지정된 value 객체와 일치하는 Map의 value객체가 있는지 확인
// 중요
Set entrySet(); // Map에 저장되어 있는 key-value쌍을 Map.Entry타입의 객체로 저장한 Set으로 반환
Set keySet(); // Map에 저장된 모든 key 객체 반환
Collection values(); // Map에 저장된 모든 vlaue 객체 반환
Object put(Object key, Object value); // Map에 key-value 묶음을 저장
void putAll(Map t); // 지정된 Map의 모든 key-value쌍을 추가한다.
Object remove(Object key); // 지정한 key 객체와 일치하는 key-value 객체를 삭제
4. 핵심 클래스 method
- ArrayList, LinkedList, HashMap
4.1. ArrayList
// 생성자
ArrayList(); // 크기가 0인 ArrayList 생성
ArrayList(Collection c); // 주어진 Collection이 저장된 ArrayList 생성
ArrayList(int initialCapacity); // 지정된 초기용량을 갖는 ArrayList 생성
// method
// 새로 본 것
Object clone(); // ArrayList 복제
void ensureCapacity(int minCapacity); // ArrayList의 용량이 최소한 minCapacity가 되도록한다.
void trimToSize(); // 용량을 크기에 맞게 줄인다. ArrayList의 빈공간을 없앤다.
// #추가
// Collection 상속
boolean add(Object o); // 지정된 객체(o)를 Collction에 추가
boolean addAll(Collection c); //Collection(c)의 객체들을 Collction에 추가
// List 상속
void add(int index, Object element); // 지정된 위치에 객체에 포함된 객체들을 추가
boolean addAll(int index, Collection c); // 지정된 위치에 컬렉션에 포함된 객체들을 추가
// #삭제
// Collection 상속
void clear(); // Collection의 모든 객체를 삭제
boolean remove(Object o); // 지정된 객체를 삭제
boolean removeAll(Collection c); // 지정된 Collection에 포함된 객체들을 삭제
boolean retainAll(Collection c); // (헷갈림 주의) Collection c 내부에 존재하는 객체가 retainAll을 하는 Collection에 존재시 해당 객체만 남기고 나머진 전부 제거
// List 상속
Object remove(int index); // 지정된 index에 있는 객체를 삭제하고 삭제된 객체를 반환
// #수정
// List 상속
Object set(int index, Object element); // 지정된 index에 객체를 저장
// #검색
// Collection 상속
boolean contains(Object o); // 지정된 객체 존재 유무 확인
boolean containsAll(Collection c); // 지정된 Collection의 객체들을 모두 포함하는지 확인
// Collection 상속
boolean isEmpty(); // Collection이 비어있는지 확인
// List 상속
Object get(int index); // 지정된 index의 객체를 반환
List subList(int fromIndex, int tolndex); // from~to까지 index의 객체 반환
int indexOf(Object o); // 지정된 객체의 index를 반환(순방향으로 찾음)
int lastIndexOf(Object o); // 지정된 객체의 index를 반환(역방향으로 찾음)
// #비교
// Collection 상속
Iterator iterator(); // Collection의 Iterator를 얻어서 반환
// List 상속
ListIterator listIterator(); // List의 객체에 접근할 수 있는 ListIterator를 반환한다.
ListIterator listIterator(int index); // index 부터 List의 객체에 접근할 수 있는 ListIterator를 반환한다.
// # 나머지
// Collection 상속
int size(); // Collection에 저장된 객체개수 반환
// List 상속
void sort(Comparator c); // 지정된 비교자로 List 정렬
//Collection 상속
Object[] toArray(); // 컬렉션에 저장된 객체를 객체배열로 반환
Object[] toArray(Object[] a); // 지정된 배열에 Collection의 객체를 저장해서 반환
// # 따로 작성 안된 것
boolean equals(Object o); // 동일한 Collection인지 비교
int hashCode(); // Collection의 hash code를 반환
4.2. LinkedList
- method는 arrayList와 거의 동일
- ArrayList 장점
- 데이터 접근 시간이 빠르다
- 구조가 간단하다.
- ArrayList 단점
- 크기를 변경할 수 없다.
- 비순차적인 데이터의 추가 삭제 시 많은 시간 소요
- LinkedList가 ArrayList 단점 해결
- 노드 이용
- 노드 하나에 다음 요소 주소 저장공간, 데이터 저장공간을 가진다.
- LinkedList 참조변수는 첫 노드의 주소와 연결되고 나머지는 노드들끼리 주소 연결
- 노드 이용
class Node{
Node next; // 다음 요소의 주소 저장
Object obj; // 데이터 저장
}
- 확장
- DoublelinkedList : 이중 연결 리스트 - 접근성 향상
- DoublyCircularLinkedList: 이중 원형 연결 리스트
- LinkedList 구현( 심화 )
4.3. Stack과 Queue
- 기본 개념
- Stack: 마지막에 저장한 data를 가장 먼저 꺼내게 되는 LIFO 구조
- Queue: 처음 저장한 data가 가장 먼저 꺼내게 되는 FIFO 구조
- 적합성
- Stack == ArrayList
- Queue == LinkedList
- Stack st = new Stack();
- Queue q = new LinkedList();
// Stack
boolean empty(); // Stack이 비었는지 확인
Object peek(); // Stack의 맨 위에 저장된 객체 반환, 객체 꺼내는 거 아님
Object pop(); // Stack의 맨 위에 저장된 객체 꺼냄
Object push(Obejct item); // Stack에 객체 (item)를 저장
int search(Object o); // Stack의 처음부터 주어진 Object를 찾아서 위치 반환, 없을 시 -1, 1부터 시작
// Queue
boolean add(Object o); // 지정된 Object Queue에 추가
Object remove(); // Queue에서 객체를 꺼내 반환
Object element(); // 삭제없이 요소를 읽어옴
boolean offer(Object o); // Queue에 객체 저장
Object poll(); // Queue에서 객체를 꺼내서 반환
Object peek(); // 삭제없이 요소를 읽어온다.
4.4. HashSet
- Set 인터페이스를 구현한 가장 대표적인 컬렉션
- 저장순서 유지를 원할 때 LinkedHashSet 사용
// 생성자
HashSet() // HashSet 객체를 생성
HashSet(Collection c) // 주어진 collection을 포함한 HashSet 객체를 생성
HashSet(int initalCapacity) // 주어진 값을 초기용량으로하는 HashSet객체를 생성
HashSet(int initalCapacity, float loadFactor) //초기용량과 load factor를 지정하는 생성자
// load factor: 저장공간이 가득 차기 전에 미리 용량을 확보하기 위한 것. 0.8이면 80% 차면 용량 2배로 늘림
// 새로 나온 것
Object clone(); // HashSet을 복제해서 반환한다.
// Collection 상속
// #추가
boolean add(Object o); // 지정된 객체(o)를 Collction에 추가
boolean addAll(Collection c); //Collection(c)의 객체들을 Collction에 추가
// #삭제
void clear(); // Collection의 모든 객체를 삭제
boolean remove(Object o); // 지정된 객체를 삭제
boolean removeAll(Collection c); // 지정된 Collection에 포함된 객체들을 삭제
boolean retainAll(Collection c); // (헷갈림 주의) Collection c 내부에 존재하는 객체가 retainAll을 하는 Collection에 존재시 해당 객체만 남기고 나머진 전부 제거
// #검색
boolean contains(Object o); //지정된 객체(o) 포함하는지 알려줌
boolean containsAll(Collection c); //Collection 내부에 저장된 모든 객체들 포함하는지 알려줌
boolean isEmpty(); // Collection이 비어있는지 확인
// #나머지
Iterator iterator(); // Collection의 Iterator를 얻어서 반환
int size(); // Collection에 저장된 객체개수 반환
Object[] toArray(); // 컬렉션에 저장된 객체를 객체배열로 반환
Object[] toArray(Object[] a) // 지정된 배열에 Collection의 객체를 저장해서 반환
// 동일 객체 false할 때 override 해야하는 것
boolean equals(Object o); // 동일한 Collection인지 비교
int hashCode(); // Collection의 hash code를 반환
2가지 주의점
- Set을 Collections를 이용해서 정렬하고 싶을 때
Set set = new HashSet();
List list = new LinkedList(set);
Collections.sort(list);
- set에 객체를 넣는데 해당 객체 필드들이 동일한 경우
- 9장에서 했던 equals, hashCode 오버라이딩 하기
public boolean equals(Object obj){
if(!(obj instanceOf class명)) return false;
class명 abc = (class명) obj;
return this.stringSomething.equals(class명.stringSomething) && this.intSomething==class명.intSomething;
}
public int hashCode(){
return Objects.hash(stringSomething, intSomething);
}
4.5 TreeSet
- 범위 검색과 정렬에 유리한 컬렉션 클래스
- 이진 탐색 트리라는 자료구조의 형태
- 정렬, 검색, 범위 검색에 높은 성능을 보이는 자료구조이다.
- 중복된 데이터 저장을 허용하지 않으며 정렬된 위치에 저장하므로 저장순서를 유지하지 않는다.
- 노드
- 2개의 다른 노드의 주소와 객체 저장을 위한 참조변수를 가지면 자신의 값을 기준으로 왼쪽 노드는 작은 값, 우측노드는 큰 값을 가진다.
- class {
TreeNode left;
Object element;
TreeNode rigth;
}
- 규칙
- add(Object o); 할 때 객체가 동일한 값을 가지면 false를 반환할 수 있도록 equals()와 hashCode()를 오버라이딩 한다.
- TreeSet이라 한들 알아서 값을 비교할 수 없다. 그래서 Comparable를 구현하지 않은 객체는 Comparable을 구현하던가 Comparator를 제공해서 객체를 비교할 방법을 제공해줘야 한다.
- 비교 기준을 주면 treeSet 내부적으로 비교 규칙에 따라서 좌측은 작은 값 우측은 큰 값의 객체 이렇게 저장을 한다.
// 생성자
TreeSet() // 기본 생성자
TreeSet(Collection c) // 주어진 collection을 저장하는 TreeSet 생성
TreeSet(Comparator comp) // 주어진 정렬조건으로 정렬하는 TreeSet 생성
TreeSet(SortedSet s) // 주어진 SortedSet collection을 저장하는 TreeSet 생성
// # 새로 나온 것
Object clone(); // TreeSet 복제해서 반환한다.
Comparator comparator(); // TreeSet의 정렬기준을 반환
NavigableSet descendingSet(); // TreeSet의 저장된 요소들을 역순으로 정렬해서 반환
// ##tree 장점과 관련된 것들
Object pollFirst(); // TreeSet의 첫번째 요소(가장 작은 값의 객체)를 반환
Object pollLast(); // TreeSet의 마지막 요소(가장 작은 값의 객체)를 반환
Object ceiling (Object obj); // obj와 동일한 객체 반환, 없으면 큰 값 중 가까운 객체 반환, 없으면 null 반환
Object floor (Object obj); // obj와 동일한 객체 반환, 없으면 작은 값 중 가까운 객체 반환, 없으면 null 반환
Object higher(Object obj); // obj보다 큰 값 중 가장 가까운 값, 없으면 null
Object lower(Object obj); // obj보다 작은 값 중 가장 가까운 값, 없으면 null
// params의 Element 의미: 객체 값의 일부분만 동일해도 상관 없다는 뜻
SortedSet headSet(Object toElement); // 지정된 객체보다 작은 값의 객체들을 반환
NavigableSet headSet(Object toElement, boolean inclusive); // 지정된 객체보다 작은 값의 객체들을 반환, inclusive true시 같은 값의 객체도 반환
SortedSet tailSet(Object fromElement); // 지정된 객체보다 큰 값의 객체들을 반환
SortedSet subSet(Object fromElement, Object toElement); // from포함 from ~ to 사이 값의 객체를 반환
NavigableSet headSet(Object toElement, boolean fromInclusive, Object toElement, boolean toInclusive); // from과 to 사이 값의 객체를 반환, true일 때 동일값 객체도 반환
Object first(); // 정렬된 순서에서 첫 번째 객체 반환
Object last(); // 정렬된 순서에서 마지막 객체 반환
// Collection 상속
// #추가
boolean add(Object o); // 지정된 객체(o)를 Collction에 추가
boolean addAll(Collection c); //Collection(c)의 객체들을 Collction에 추가
// #삭제
void clear(); // Collection의 모든 객체를 삭제
boolean remove(Object o); // 지정된 객체를 삭제
boolean removeAll(Collection c); // 지정된 Collection에 포함된 객체들을 삭제
boolean retainAll(Collection c); // (헷갈림 주의) Collection c 내부에 존재하는 객체가 retainAll을 하는 Collection에 존재시 해당 객체만 남기고 나머진 전부 제거
// #검색
boolean contains(Object o); //지정된 객체(o) 포함하는지 알려줌
boolean containsAll(Collection c); //Collection 내부에 저장된 모든 객체들 포함하는지 알려줌
boolean isEmpty(); // Collection이 비어있는지 확인
// #나머지
Iterator iterator(); // Collection의 Iterator를 얻어서 반환
int size(); // Collection에 저장된 객체개수 반환
Object[] toArray(); // 컬렉션에 저장된 객체를 객체배열로 반환
Object[] toArray(Object[] a) // 지정된 배열에 Collection의 객체를 저장해서 반환
// 동일 객체 false할 때 override 해야하는 것
boolean equals(Object o); // 동일한 Collection인지 비교
int hashCode(); // Collection의 hash code를 반환
4.6 HashMap과 Hashtable
해싱 원리
- 해싱은 해시함수를 이용해서 데이터를 해시 테이블에 저장하고 검색하는 기법
- key를 통해서 value를 빠르게 찾고 싶어서 만든 구조
- 작동
- key -> [해시 함수] -> 해시코드(== Array index)
key를 해시 함수에 넣고 해시 코드로 반환 (해시 테이블의 배열의 index) - 해시코드 -> (해시 테이블의 배열의 index)[해시 테이블] -> [key / value] 중 원하는 것을 반환
해시코드 == 해시 테이블의 인덱스이고 hash table 내부에 key와 value가 둘 다 저장되어있다.
- key -> [해시 함수] -> 해시코드(== Array index)
해싱 원리를 구현한 클래스
- Hashtable, HashMap이 해싱 원리를 구현한 class
- * Hashtable과 hash table은 다르다. 띄어쓰기 차이
예시
Map map = new HashMap();
map.put("key", "value");
- HashMap 자체가 내부적으로 해싱 기법이 적용이 된 상태
- 원리
- map에 key, value를 넣는다.
- key가 해시 함수에 들어가서 hashcode를 반환
- 객체의 hashcode가 아니다. 함수를 통해서 만들어진 새로운 정수를 hashcode라고 명할 뿐이다.
- 이름을 이렇게 지은 이유는 실제 HashMap의 해싱 기법은 해시 함수를 돌릴 때 Objects.hash()를 통해서 객체 여러 개의 해시코드를 받고(hashcode() 이용) 그것들을 조합을 해서 나온 값을 key의 hashcode로 만들기 때문
- HashMap에 이미 만들어진 bucket(==hash table)이 존재하는데 hashcode(key로부터 나온 것)로 bucket의 인덱스와 일치한 위치를 찾는다.
- 해당 bucket 위치에 key와 value를 넣는 2가지 공간이 존재하는데 이곳에 넣으려고 한 "key", "value"를 해당 위치에 맞는 곳에 집어넣는다.
- 사용 시 key를 통해서 bucket 위치를 찾고 뒤에 나올 method를 통해서 entry를 반환할지, key를 반환할지, value를 반환할지 결정한다.
// 생성자
HashMap(); // HashMap 객체를 생성
HashMap(int initialCapacity); // 지정된 값을 초기용량으로 하는 객체 생성
HashMap(int initialCapacity, float loadFactor); // 초기용량, 로드팩터
HashMap(Map m); // 지정된 Map의 모든 요소를 포함하는 HashMap 생성
// 새로 생긴 것
Object clone(); // 현재 hashMap을 복제 반환
// #검색
Object get(Object key); // 지정된 키의 값을 반환, 키 못찾으면 null
Object getOrDefault(Object key, Object defaultValue); // 지정된 키의 값을 반환, 키 못찾으면 default 객체 반환
// #대체
Object replace(Object key, Object value); // 지정된 키의 값을 지정된 값으로 대체
boolean replace(Object key, Object oldValue, Object newValue); // 키와 oldValue가 일치시 newValue로 대체
// Map 상속
// #중요, 읽기만 가능
Set entrySet(); // Map에 저장되어 있는 key-value쌍을 Map.Entry타입의 객체로 저장한 Set으로 반환
Set keySet(); // Map에 저장된 모든 key 객체 반환
Collection values(); // Map에 저장된 모든 vlaue 객체 반환
// #추가
Object put(Object key, Object value); // Map에 key-value 묶음을 저장
void putAll(Map t); // 지정된 Map의 모든 key-value쌍을 추가한다.
// #삭제
void clear(); // Map의 모든 객체를 삭제
Object remove(Object key); // 지정한 key 객체와 일치하는 key-value 객체를 삭제
// #검색
boolean containsKey(Object key); // 지정된 key 객체와 일치하느 Map의 key객체가 있는지 확인
booelan containsValue(Object value); // 지정된 value 객체와 일치하는 Map의 value객체가 있는지 확인
// #나머지
boolean isEmpty(); // Map이 비었는지 확인
int size(); // Map에 저장된 key-value쌍의 개수를 반환
5. 컬렉션 서브 method
5.1. Iterator, ListIterator, Enumeration
- 컬렉션에 저장된 요소를 접근하는 데 사용되는 인터페이스
- 종류
- Enumeration: Iterator의 구버전
- Iterator: 컬렉션에 저장된 요소를 접근하는데 사용되는 인터페이스
- ListIterator: Iterator에 양방향 조회기능추가(List 구현시에만 사용가능)
- 작동원리
- Iterable
- 인터페이스
- iterator() 메서드를 선언. 해당 인터페이스를 상속하는 class들은 iterator를 구현해야만 한다.
- iterator()
- 컬렉션 내부에 구현된 Iterator class를 이용해서 Iterator type으로 변환해 주는 역할
- Iterator가 iterator는 아니다. 오해하지 말 것
- 각 Collection의 class 내부에 들어가 보면 private class로 Iterator가 구현되어 있다.
- 1회성 method로 다시 사용하고 싶을 때 다시 method 호출이 필요
- Iterator
- 인터페이스
- Collection에 저장된 요소를 읽어오는 것을 표준화한 것이고, 데이터를 하나씩 읽을 때 사용한다.
- hasNext(), next() 메서드가 존재한다.
- Iterable
- method
boolean hasNext(); // 읽어올 요소가 있는지 확인
Object next(); // 읽어올 요소가 존재시 다음 요소 읽기
object remove(); // 읽어온 요소 삭제
- 사용 예
Iterator iterator = list.iterator(); // iterator는 1회성이다
while (iterator.hasNext()) {
iterator.next();
iterator.remove();
}
5.2. Map과 Iterator
- Map은 Collection 인터페이스를 상속받지 않으므로 iterator() 메서드를 따로 구현하지 않아 iterator 사용이 불가
- type을 Set 혹은 Collection으로 변경 후 iterator()를 사용 가능
- entrySet() -> Set
- keySet() -> Set
- values() -> Collection
Iterator iterator = map.keySet().iterator(); // 한줄로 작성 가능
// Set set = map.keySet();
// Iterator iterator = set.iterator();
Iterator iterator1 = map.values().iterator();
Iterator iterator2 = map.entrySet().iterator();
5.3. Comparator과 Comparable
매우 헷갈림-자주 볼 것
무조건 봐야 하는 블로그 : https://st-lab.tistory.com/243
- 해당 인터페이스들 사용 목적
- 자료형 타입과 같은 경우 비교 연산자를 통해서 크고 작음을 비교가 가능
- 반면 객체는 비교 연사자를 통한 비교가 불가
- new Car(1); < new Car(2); -> 말이 안 됨
- 객체를 비교하기 위해서 Comparable, Comparator 사용
- Comparable, Comparator 차이점
- Comparable: 자신과 다른 객체 비교
- 비교 method: compareTo(Object o); 선언
- 대부분 비교가능한 자료형 및 참조형 타입에 미리 implements 되어 있다.
- 선언되지 않은 참조변수가 Comparable를 사용하기 위해선 해당 인터페이스를 implements 하면 된다.
- Comparator: A객체와 B 객체 비교
- 비교 method: compare(Object A, Object B); 선언
- 필요할 때 자신이 직접 규칙을 생성해서 만들어야 함.
- Comparable: 자신과 다른 객체 비교
public interface Comparable{
int comparTo(Object o);
}
public interface Comparator{
int compare(Object o1, Object o2);
}
- Comparable, Comparator 공통점
- 비교하는 대상 (this vs o) , (o1 vs o2)가 존재 시 좌측이 크면 양수, 작으면 음수, 동일하면 0을 반환한다.
- 생각해 보면 좌측-우측 값이 양수면 좌측이 큰 것이고 음수면 작은 것이므로 아래 예시와 같이 this.x-o.x로 작성이 가능
- 하지만 overflow가 발생할 수 있으므로 크게 추천하는 방법이 아니다.
- 비교 시 객체 자체를 비교하는 것이 아니라 객체 내부의 자료형을 추출해서 자료형 끼리 비교한다.
- 비교하는 대상 (this vs o) , (o1 vs o2)가 존재 시 좌측이 크면 양수, 작으면 음수, 동일하면 0을 반환한다.
Compareable 예시
class Abc implements Comparable<Abc>{ // 지네릭스를 사용하여 해당 타입끼리만 비교
int x;
char[] chars = {'a', 'b', 'c'};
@Override
public int compareTo(Abc o) {
// 객체자체를 비교 하지 않고 객체 내부의 자료형끼리 비교한다.
if(this.x > o.x) return 1; // 꼭 1이 아니라 양수를 작성해도 된다.
if(this.x < o.x) return -1; // 음수면 된다.
return 0;
// 아래와 같이 1줄로 작성 가능
// return this.x-o.x;
}
}
Comparator 예시
class Abc{
int x;
char[] chars = {'a', 'b', 'c'};
}
//Comparator은 Abc객체 2개와 비교하는 것이여서 AbcComparator라는 새 class에 Comparator를 구현하고
// 이 클래스객체를 이용해서 Abc를 비교한다.
// 익명 객체를 만들어서 class를 생성하지 않고 하는 방법이 존재한다.
class AbcComparator implements Comparator<Abc> {
@Override
public int compare(Abc a, Abc b){
return a.x-b.x;
}
}
- 사용방법
- Comparable과 Comparator 메서드 자체를 이용해서 양수, 음수, 0의 값을 return 받고
if 양수일 때, if 음수일 때, if 0일 때 조건문을 통해서 비교한 결과를 이용하는 방법이 존재 - Sort() 이용하는 방법 - 매우 자주 사용
- Sort()
- Arrays, List, Collections 2가지 타입이 가지고 있는 정렬 메서드이다.
- Arrays sort의 매개변수에 들어갈 수 있는 객체는 배열, 비교체는 Comparator
- List의 sort()는 매개변수로 Comparator를 받음
- Collections의 매개변수에 들어 갈 수 있는 객체는 list type 객체이다.
- 조금씩 다르지만 근본적인 원리는 동일하다. 배열 내부의 값을 비교해서 오름차순으로 나열한다.
- 비교방식
- Sort(Object [] a); // a 타입의 참조변수가 가진 Comparable의 comparetor()의 규칙에 따라서 오름차순 정렬을 해준다.
- Sort(Object[] a, Comparator c); // Comparator를 구현한 클래스 중에서 매개변수로 넣은 Comparator 클래스의 규칙에 따라서 Object a를 오름차순으로 정렬을 해준다.
- Arrays, List, Collections 2가지 타입이 가지고 있는 정렬 메서드이다.
- Sort()
- Comparable과 Comparator 메서드 자체를 이용해서 양수, 음수, 0의 값을 return 받고
Compable 사용 예
import java.util.*;
class Practice8 {
public static void main(String[] args) {
Abc[] abcs = {new Abc(3),new Abc(2), new Abc(1)};
for (int i = 0; i < abcs.length; i++) {
System.out.println("abcs = " + abcs[i].x);
}
Arrays.sort(abcs);
for (int i = 0; i < abcs.length; i++) {
System.out.println("abcs = " + abcs[i].x);
}
}
}
class Abc implements Comparable<Abc>{
int x;
char[] chars = {'a', 'b', 'c'};
Abc(int x){
this.x = x;
}
@Override
public int compareTo(Abc o) {
return this.x-o.x;
}
}
Comparator 사용 예
import java.util.*;
class Practice8 {
public static void main(String[] args) {
Abc[] abcs = {new Abc(3),new Abc(2), new Abc(1)};
for (int i = 0; i < abcs.length; i++) {
System.out.println("abcs = " + abcs[i].x);
}
Arrays.sort(abcs, new AbcComparator());
for (int i = 0; i < abcs.length; i++) {
System.out.println("abcs = " + abcs[i].x);
}
}
}
class Abc{
int x;
char[] chars = {'a', 'b', 'c'};
Abc(int x){
this.x = x;
}
}
class AbcComparator implements Comparator<Abc> {
@Override
public int compare(Abc a, Abc b){
return a.x-b.x;
}
}
6. java.util class
6.1. Arrays
- 헷갈렸던 부분 다시 잡기
- Array와 Arrays
- Array
- 정적 배열
- 길이가 고정
- 기본형, 참조형 모든 것을 받을 수 있다.
- 하지만 Method가 따로 존재하지 않는다.
- Arrays
- Array를 다루기 위한 Array 조작 기능을 가진 class
- 모두 static method이다.
- 비슷한 class 유형으로 Objects, Collections 존재
- Array
- ArrayList
* ArrayList 뿐만 아니라 CollectionFramework 특징, ArrayList라고 한 것은 Array랑 ArrayList랑 헷갈리기 쉬워서 대표로 적은 것
- 가변 배열
- 길이가 고정되어있지 않다
- 객체와 Collection 받는다.
- 객체만 받는다고는 하지만 오토박싱으로 인해서 자료형 값도 받을 수 있다. 하지만 type은 객체 type이다.
- Arrays method
static String toString(arr[]); // String으로 나옴
static String deepToString(arr[][]); // 이차원 배열 일때, String으로 나옴
// overloading되면서 너무 다양한 반환 타입이 존재해서 아래 method들 반환 타입 생략
static copyOf(variable, int); // 0 부터 int까지 array 추출
static copyOfRange(variable, int from, int to); // array의 시작과 끝 추출
static fill(arr, int i); // 배열의 모든 요소를 지정된 값으로 채운다.
static setAll(arr, 람다식); // 배열을 채우는데 사용할 함수형 인터페이스를 매개변수로 받는다.
static sort(arr[]); // 배열 정렬 작은것 부터 순서대로
static binarySearch(index); // 배열이 정렬된 상태에서 index에 위치한 값을 찾아낸다. 이진 검색을 하는 방식으로 속도가 빠름
static equals(arr[],arr2[]); // 두배열 비교
static equals(arr[][],arr2[][]); // 2차원 배열 비교
static List asList(Object...a); // 가변 매개변수. 배열 생성 없이 list에 담아서 반환
// 예시
List list = Arrays.asList(1,2,3,4); // list 변경 불가
List list = new ArrayList(Arrays.asList(1,2,3,4)); //list 변경 가능
6.2. Collections
- Collection framework의 구현 객체에게 유용한 method를 주는 class
1. 멀티 쓰레드로 인해서 동기화가 필요시 사용하는 method
static Collection synchronizedCollection (Collection c)
static List synchronizedList (List l)
static Set synchronizedSet (Set s)
static Map synchronizedMap (Map m)
static SortedSet synchronizedSortedSet (SortedSet s)
static SortedMap synchronizedSortedMap (SortedMap m)
2. 변경 불가한 컬렉션 만들기 == 읽기 전용
static Collection unmodifiableCollection (Collection c)
static List unmodifiableList (List l)
static Set unmodifiableSet (Set s)
static Map unmodifiableMap (Map m)
static NavigableSet unmodifiableNavigableSet(NavigableSet s)
static SortedSet unmodifiableSortedSet (SortedSet s)
static NavigableMap unmodifiableNavigableMap(NavigableMap m)
static SortedMap unmodifiableSortedMap (SortedMap m)
3. 싱글톤 컬렉션 만들기
static List singleton(Object o);
static Set singleton(Object o);
static map singletonMap(Object key, Object value);
4. 한 종류의 객체(한 가지 type)만 저장하는 컬렉션 만들기
static Collection checkedCollection (Collection c, Class type)
static List checkedList (List list, Class type)
static Set checkedSet (Set s, Class type)
static Map checkedMap(Map m, Class keyType, Class valueType)
static Queue checkedQueue(Queue queue, Class type)
static NavigableSet checkedNavigableSet(NavigableSet s, Class type)
static SortedSet checkedSortedSet (SortedSet s, Class type)
static NavigableMap checkedNavigableMap(NavigableMap m, Class keyType, Class valueType)
static SortedMap checkedSortedMap (SortedMap m, Class keyType, Class valueType)
5. 추가 메서드
Collections.shuffle()
Collections.sort(List)
그냥 공부하다가 끄적인 것
collection framework는 객체만 받는 collection이다.
그래서 list, set, map의 class들은 값을 받을 때 실질적으로 object를 받아야 하고 저장되는 것은 object의 주소이다.
하지만 기본형, String을 추가할 때 내부적으로는 객체의 주소가 저장되지만 (오토박싱으로 객체로 저장가능) print를 통해 console 창에 찍힌 값은 객체주소가 아닌 실제 입력 값이 보기 좋게 나온다.
그래서 우선 언제 값이 나오고 언제 주소가 나오는지 확인을 하고 싶었고
두 번째로는 collection framework와 관련된 method들의 params는 크게 Object와 Collection을 받는다.
받는 값이 무엇이냐에 따라서 어떤 차이가 있는지 확인하고 싶었다.
add(Object obj) addAll(Collection c)를 예를 들어 사용했다.
params가 obj일 때 1) object 가 들어오면 1) 기본형 타입, String 타입은 값으로 나옴
2) 참조형 타입이 오면 객체 주소로 나옴
3) map은 { }를 달고 나옴
2) collection 구현클래스가 오면 1) list, set 은 []를 달고 나옴 [ 1, 2, [list], [1,2,3] ]
params가 collection 일 때 일단 collection 구현 클래스 외적인 것들은 거르고 값이 들어올 때 딱 객체로만 들어옴,
* [ ]이런 거 안 달고 들어옴
물론 들어오기 전 객체가 기본형 타입, String 타입이면 값으로 나오고 참조형 타입이면 객체 주소로 나옴
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import javax.print.attribute.standard.Media;
public class prac1 {
public static void main(String[] args) {
// 일반 객체 생성
Car1 c = new Car1();
// collection framework의 class 생성
HashMap hashMap = new HashMap();
hashMap.put("key", "value");
System.out.println("hashmap: " + hashMap);
System.out.println();
// list2 collection 생성
ArrayList list2 = new ArrayList();
list2.add("Object");
System.out.println("list2: " + list2);
System.out.println();
// list1 collectioin 생성
ArrayList list1 = new ArrayList<>(10);
list1.add("Object1");
list1.add("Object2");
list1.add("Object3");
System.out.println("list1: " + list1);
System.out.println();
// 자기 자신을 넣을 때
list1.addAll(list1);
System.out.println("list1.addAll(list1): " + list1);
System.out.println();
list1.add(list1);
System.out.println("list1.add(list1): " + list1);
System.out.println();
// 원상복구
list1.remove(3);
list1.remove(3);
list1.remove(3);
list1.remove(3);
System.out.println("list1: " + list1);
System.out.println();
System.out.println();
// 다른 list를 넣을 때
list1.add(list2);
System.out.println("list1.add(list2): " + list1); // add는 Object를 추가 [Object]를 객체로 인식. 그래도 collection 이기 때문에 주소로 안나오고 값으로 보여짐
System.out.println();
list1.addAll(list2);
System.out.println("list1.addAll(list2): " + list1); // addAll은 collection의 객체만 저장하기 때문
System.out.println();
// 복구
list1.remove(3);
list1.remove(3);
System.out.println("list1: " + list1);
System.out.println();
System.out.println();
// real 객체를 넣을 때
list1.add(c);
System.out.println("list1.add(c): " + list1);
System.out.println();
// list1.addAll(c); // collecion class 아니여서 error
System.out.println();
// map을 넣을 때 - 주소가 나오는지 값이 나오는지 궁금해서
list1.add(hashMap);
System.out.println("list1.add(hashMap): " + list1);
System.out.println();
list1.add(hashMap.entrySet()); //settype으로 변경 후 출력
System.out.println("list1.add(hashMap.entrySet()): " + list1);
list1.addAll(hashMap.entrySet()); //settype으로 변경 후 출력
System.out.println("list1.addAll(hashMap.entrySet()): "+ list1);
}
}
class Car1 {
String x;
int y;
}
-console-
hashmap: {key=value}
list2: [Object]
list1: [Object1, Object2, Object3]
list1.addAll(list1): [Object1, Object2, Object3, Object1, Object2, Object3]
list1.add(list1): [Object1, Object2, Object3, Object1, Object2, Object3, (this Collection)]
list1: [Object1, Object2, Object3]
list1.add(list2): [Object1, Object2, Object3, [Object]]
list1.addAll(list2): [Object1, Object2, Object3, [Object], Object]
list1: [Object1, Object2, Object3]
list1.add(c): [Object1, Object2, Object3, .Car1@251a69d7]
list1.add(hashMap): [Object1, Object2, Object3, .Car1@251a69d7, {key=value}]
list1.add(hashMap.entrySet()): [Object1, Object2, Object3, .Car1@251a69d7, {key=value}, [key=value]]
list1.addAll(hashMap.entrySet()): [Object1, Object2, Object3, .Car1@251a69d7, {key=value}, [key=value], key=value]
이전 발행글: 10. 날짜와 시간 & 형상화
다음 발행글: 12. 지네릭스, 열거형, 어노테이션