티스토리 뷰

Java

java - 14 ) 컬렉션 프레임워크

kingsubin 2020. 8. 28. 15:33

컬렉션 프레임워크의 개념

 

컬렉션 프레임워크란 ?

- 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합

  즉, 데이터를 저장하는 자료 구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현해 놓은 것이다.

  이러한 컬렉션 프레임워크는 자바의 인터페이스를 사용하여 구현된다.

 

컬렉션 프레임워크 주요 인터페이스

- List, Set, Map

  List, Set은 모두 Collection 인터페이스를 상속받지만, 구조상의 차이로 인해 Map 인터페이스는 별도로 정의된다.

 

주요 인터페이스의 간략한 특징

List<E> : 순서가 있는 데이터의 집합, 중복을 허용함 

- Vector, ArrayList, LinkedList, Stack, Queue

 

Set<E> : 순서가 없는 데이터의 집합, 중복 허용하지 않음

- HashSet, TreeSet

 

Map<K, V> : 키와 값의 한 쌍으로 이루어지는 데이터의 집합, 순서가 없음, 키는 중복 허용하지 않지만, 값은 중복 가능

- HashMap, TreeMap, Hashtable, Properties

 

Collection 인터페이스

- List, Set 인터페이스의 많은 공통된 부분을 Collection 인터페이스에서 정의하고, 두 인터페이스는 그것을 상속받는다.

  따라서 Collection 인터페이스는 컬렉션을 다루는데 가장 기본적인 동작을 정의하고, 메소드를 제공한다.

 

- method

boolean add(E e);

void clear();

boolean contains(Object o);

boolean equals(Object o);

boolean isEmpty();

Iterator<E> iterator();

boolean remove(Object o);

int size();

Object[] toArray();


 

List 컬렉션 클래스

 

List 컬렉션 클래스

1. 요소의 저장 순서가 유지된다.

2. 같은 요소의 중복 저장을 허용한다.

 

- 대표적인 List 컬렉션 클래스에 속하는 클래스

1. ArrayList

2. LinkedList

3. Vector

4. Stack

 

ArrayList<E> 

- ArrayList는 배열을 이용하기 때문에 인덱스를 이용해 배열 요소에 빠르게 접근할 수 있다.

  

ArrayList<Integer> arrList = new ArrayList<Integer>();
 
// add() 메소드를 이용한 요소의 저장
arrList.add(40);
arrList.add(20);
arrList.add(30);
arrList.add(10);
 
// for 문과 get() 메소드를 이용한 요소의 출력
for (int i = 0; i < arrList.size(); i++) {
    System.out.print(arrList.get(i) + " ");
}
 
// remove() 메소드를 이용한 요소의 제거
arrList.remove(1);
 
// Enhanced for 문과 get() 메소드를 이용한 요소의 출력
for (int e : arrList) {
    System.out.print(e + " ");
}
 
// Collections.sort() 메소드를 이용한 요소의 정렬
Collections.sort(arrList);
 
// iterator() 메소드와 get() 메소드를 이용한 요소의 출력
Iterator<Integer> iter = arrList.iterator();
while (iter.hasNext()) {
    System.out.print(iter.next() + " ");
}
 
// set() 메소드를 이용한 요소의 변경
arrList.set(0, 20);
 
for (int e : arrList) {
    System.out.print(e + " ");
}
 
// size() 메소드를 이용한 요소의 총 개수
System.out.println("리스트의 크기 : " + arrList.size());

=>

40 20 30 10

40 30 10

10 30 40 

20 30 40

리스트의 크기 : 3

 

LinkedList<E>

- ArrayList 클래스가 배열을 이용하여 요소를 저장함으로써 발생하는 단점을 극복하기 위해 고안됬다.

  내부적으로 연결 리스트 (linked list)를 이용하여 요소를 저장한다.

 

- ArrayList 와 차이는 사용 방법이 아닌, 내부적으로 요소를 저장하는 방법에 있다.

 

- 단일 연결 리스트는 현재 요소에서 이전 요소로 접근하기가 매우 어렵다.

  따라서 이전 요소를 가리키는 참조도 가지는 이중 연결 리스트 (doubly linked list)가 좀 더 많이 사용된다.

 

- LinkedList 클래스도 위와 같은 이중 연결 리스트를 내부적으로 구현한 것이다.

  또한, LinkedList 클래스 역시 List 인터페이스를 구현하므로, ArrayList 클래스와 사용할 수 있는 메소드가 거의 같다.

 

LinkedList<String> lnkList = new LinkedList<String>();
 
// add() 메소드를 이용한 요소의 저장
lnkList.add("넷");
lnkList.add("둘");
lnkList.add("셋");
lnkList.add("하나");
 
// for 문과 get() 메소드를 이용한 요소의 출력
for (int i = 0; i < lnkList.size(); i++) {
    System.out.print(lnkList.get(i) + " ");
}
 
// remove() 메소드를 이용한 요소의 제거
lnkList.remove(1);
 
// Enhanced for 문과 get() 메소드를 이용한 요소의 출력
for (String e : lnkList) {
    System.out.print(e + " ");
}
 
// set() 메소드를 이용한 요소의 변경
lnkList.set(2, "둘");
 
for (String e : lnkList) {
    System.out.print(e + " ");
}
 
// size() 메소드를 이용한 요소의 총 개수
System.out.println("리스트의 크기 : " + lnkList.size());

=> 

넷 둘 셋 하나

넷 셋 하나

넷 셋 둘

리스트의 크기 : 3

 

List 인터페이스 메소드

 

 


 

Stack과 Queue

 

Stack<E> 클래스

- Stack 클래스는 List 컬렉션 클래스의 Vector 클래스를 상속받아, 전형적인 스택 메모리 구조의 클래스를 제공한다.

  

스택 메모리 구조는 선형 메모리 공간에 데이터를 저장하면서 후입선출 (LIFO)의 자료구조이다.

즉, 가장 나중에 저장된(push) 데이터가 가장 먼저 인출(pop)되는 구조이다.

 

 

메소드

 

 

Queue<E> 인터페이스

- 클래스로 구현된 스택과는 달리 자바에서 큐 메모리 구조는 별도의 인터페이스 형태로 제공된다.

  

Queue 인터페이스를 상속받는 하위 인터페이스

1. Deque

2. BlockingDeque

3. BlockingQueue

4. TransferQueue

- Deque 인터페이스를 구현한 LinkedList 클래스가 큐 메모리 구조를 구현하는 데 가장 많이 사용된다.

 

큐 메모리 구조는 선형 메모리 공간에 데이터를 저장하면서 선입선출 (FIFO)의 자료구조이다.

즉, 가장 먼저 저장된 (push) 데이터가 가장 먼저 인출 (pop)되는 구조이다.

 

 

메소드

 

 


 

Set 컬렉션 클래스

 

Set 컬렉션 클래스

1. 요소의 저장 순서를 유지하지 않는다.

2. 같은 요소의 중복 저장을 허용하지 않는다.

 

- 대표적인 Set 컬렉션 클래스에 속하는 클래스

1. HashSet

2. TreeSet

 

HashSet<E>

- HashSet 클래스는 Set 컬렉션 클래스에서 가장 많이 사용되는 클래스 중 하나이다.

  해시 알고리즘 (hash algorithm)을 사용하여 검색 속도가 매우 빠르다.

  이러한 HashSet 클래스는 내부적으로 HashMap 인스턴스를 이용하여 요소를 저장한다.

 

- HashSet에 이미 존재하는 요소인지를 파악하기 위해서는 내부적으로 다음과 같은 과정을 거친다.

1. 해당 요소에서 hashCode() 메소드를 호출하여 반환된 해시값으로 검색할 범위를 결정한다.

2. 해당 범위 내의 요소들을 equals() 메소드로 비교한다.

 

따라서 HashSet에서 add() 메소드를 사용하여 중복 없이 새로운 요소를 추가하기 위해서는

hashCode()와 equals() 메소드를 상황에 맞게 오버라이딩 해야한다.

 

 

해시 알고리즘 (hash algorithm)

- 해시 알고리즘이란 해시 함수를 사용하여 데이터를 해시 테이블에 저장하고, 다시 그것을 검색하는 알고리즘이다.

 

 

 

TreeSet<E>

- TreeSet 클래스는 데이터가 정렬된 상태로 저장되는 이진 검색 트리 (binary search tree)의 형태로 요소를 저장한다.

  이진 검색 트리는 데이터를 추가하거나 제거하는 등의 기본 동작 시간이 매우 빠르다.

  

- TreeSet 인스턴스에 저장되는 요소들은 모두 정렬된 상태로 저장된다.

 

Set 인터페이스 메소드

 

 

 


 

Map 컬렉션 클래스

 

Map 컬렉션 클래스

- Map 인터페이스는 Collection 인터페이스와는 다른 저장 방식을 가진다.

  Map 컬렉션 클래스들은 키와 값을 하나의 쌍으로 저장하는 방식 (key-value) 을 사용한다.

 

1. 요소의 저장 순서를 유지하지 않는다.

2. 키는 중복을 허용하지 않지만, 값의 중복은 허용한다.

 

Map 컬렉션 클래스에 속하는 클래스

1. HashMap

2. Hashtable

3. TreeMap

 

HashMap<K, V>

- Map 컬렉션 클래스에서 가장 많이 사용되는 클래스 중 하나

   해시 알고리즘을 사용하여 검색 속도가 매우 빠르다.

 

- 메소드

 

Hashtable<K, V> 

- HashMap 클래스와 같은 동작을 하는 클래스이다.

  기존 코드와의 호환성을 위해서만 남아있으므로, HashMap 클래스 사용하는 것이 더 좋다.

 

TreeMap<K, V>

- TreeMap 클래스는 키와 값을 한 쌍으로 하는 데이터를 이진 검색 트리 (binary search tree)의 형태로 저장한다.

  이진 검색 트리는 데이터를 추가하거나 제거하는 등의 기본 동작 시간이 매우 빠르다

 

 


Iterator와 ListIterator

 

Iterator<E>인터페이스

- 자바의 컬렉션 프레임워크는 컬렉션에 저장된 요소를 읽어오는 방법을 Iterator 인터페이스로 표준화하고 있다.

  Collection 인터페이스에서는 Iterator 인터페이스를 구현한 클래스의 인스턴스를 반환하는 iterator() 메소드를 정의하여 

  각 요소에 접근하도록 하고 있다.

  따라서 Collection 인터페이스를 상속받는 List와 Set 인터페이스에서도 iterator() 메소드를 사용할 수 있다.

  

LinkedList<Integer> lnkList = new LinkedList<Integer>();
 
lnkList.add(4);
lnkList.add(2);
lnkList.add(3);
lnkList.add(1);
 
Iterator<Integer> iter = lnkList.iterator();
while (iter.hasNext()) {
    System.out.print(iter.next() + " ");
}

=> 4 2 3 1

 

- Iterator 인터페이스 method 

boolean hasNext();

E next();

default void remove();

 

Enumeration<E> 인터페이스

- Enumeration 인터페이스는 JDK 1.0부터 사용해 온 Iterator 인터페이스와 같은 동작을 하는 인터페이스다.

  Enumeration 인터페이스는 hasMoreElements(), nextElement() 메소드를 사용하여 Iterator 와 같은 작업을 한다.

  하지만 현재에는 기존 코드와의 호환성을 위해서만 남아있으므로, Iterator 인터페이스를 사용하는 것이 더 좋다.

 

ListIterator<E> 인터페이스

- ListIterator 인터페이스는 Iterator 인터페이스를 상속받아 여러 기능을 추가한 인터페이스다.

  Iterator 인터페이스는 컬렉션의 요소에 접근할 때 한 방향으로만 이동할 수 있다.

  하지만 ListIterator 인터페이스는 컬렉션 요소의 대체, 추가, 인덱스 검색 등을 위한 작업에서

  양방향으로 이동하는 것을 지원한다.

  단, ListIterator 인터페이스는 List 인터페이스를 구현한 List 컬렉션 클래스에서만 listIterator() 메소드를 통해 사용할 수 있다.

 

LinkedList<Integer> lnkList = new LinkedList<Integer>();
 
lnkList.add(4);
lnkList.add(2);
lnkList.add(3);
lnkList.add(1);
 
ListIterator<Integer> iter = lnkList.listIterator();
while (iter.hasNext()) {
    System.out.print(iter.next() + " ");
}
 
while (iter.hasPrevious()) {
    System.out.print(iter.previous() + " ");
}

=> 4 2 3 1 

     1 3 2 4 

 

- method

void add();

boolean hasNext();

boolean hasPrevious();

E next();

E previous();

void remove();

...


Comparable과 Comparator

 

Comparable<T> 인터페이스 (java.lang.Comparable)

- Comparable 인터페이스는 객체를 정렬하는 데 사용되는 메소드인 compareTo() 메소드를 정의하고 있다.

  자바에서 같은 타입의 인스턴스를 서로 비교해야만 하는 클래스들은 모두 Comparable 인터페이스를 구현하고 있다.

  따라서 Boolean을 제외한 래퍼 클래스나 String, Time, Date 와 같은 클래스의 인스턴스는 모두 정렬 가능하다.

  기본 정렬 순서는 오름차순이다.

 

- 정렬 수행 시 기본적으로 적용되는 정렬 기준이 되는 메소드를 정의하는 인터페이스 

 

- 정렬할 객체에 Comparable interfacef를 구현한 후, compareTo() 메소드를 오버라이드하여 구현한다.

- compareTo() 작성법

  - 현재 객체 < 파라미터로 넘어온 객체 : 음수

  - 현재 객체 == 파라미터로 넘어온 객체 : 0 

  - 현재 객체 > 파라미터로 넘어온 객체 : 양수

  - 음수 또는 0이면 객체의 자리가 그대로 유지, 양수인 경우에는 두 객체의 자리가 바뀜

 

class Car implements Comparable<Car> {
    private String modelName;
    private int modelYear;
    private String color;
 
    Car(String mn, int my, String c) {
        this.modelName = mn;
        this.modelYear = my;
        this.color = c;
    }
 
    public String getModel() {
        return this.modelYear + "식 " + this.modelName + " " + this.color;
    }
 
    public int compareTo(Car obj) {
        if (this.modelYear == obj.modelYear) {
            return 0;
        } else if(this.modelYear < obj.modelYear) {
            return -1;
        } else {
            return 1;
        }
    }
}
 
public class Comparable01 {
    public static void main(String[] args) {
        Car car01 = new Car("아반떼", 2016, "노란색");
        Car car02 = new Car("소나타", 2010, "흰색");
 
        System.out.println(car01.compareTo(car02));
    }
}

=> 1

 

Comparator<T> 인터페이스 (java.uitl.Comparator)

- Comparator 인터페이스는 Comparable 인터페이스와 같이 객체를 정렬하는데 사용되는 인터페이스다.

  Comparable은 기본적으로 오름차순이다.

  반면에 Comparator 인터페이스는 내림차순이나 아니면 다른 기준으로 정렬하고 싶을 때 사용할 수 있다.

  즉, Comparator 인터페이스를 구현하면 오름차순 이외의 기준으로도 정렬할 수 있다.

  이때 Comparator 인터페이스를 구현한 클래스에서는 compare() 메소드를 재정의하여 사용한다.

 

- 정렬할 객체에 Comparator interfacef를 구현한 후, compare() 메소드를 오버라이드한 클래스를 작성한다.

- compare() 작성법

  - 첫 번째 파라미터로 넘어온 객체 < 두 번 째 파라미터로 넘어온 객체 : 음수

  - 첫 번째 파라미터로 넘어온 객체 == 두 번 째 파라미터로 넘어온 객체 : 0

  - 첫 번째 파라미터로 넘어온 객체 > 두 번 째 파라미터로 넘어온 객체 : 양수

  - 음수 또는 0이면 객체의 자리가 그대로 유지, 양수인 경우에는 두 객체의 자리가 바뀜

 

Collections.sort(list, new Comparator() {
			@Override
			public int compare(String s1, String s2) {
				if (s1.length() > s2.length())
					return 1;
				else if (s1.length() < s2.length())
					return -1;
				else
					return s1.compareTo(s2);
			}
		});

 

 

 

 

 


※출처

tcpschool.com/java/java_collectionFramework_concept