가자미의 개발이야기

자바 컬렉션 프레임워크-List<E> : ArrayList, LinkedList, Stack, Queue 본문

Java/자바 기본 문법

자바 컬렉션 프레임워크-List<E> : ArrayList, LinkedList, Stack, Queue

가자미 2021. 2. 2. 13:48

a. 컬렉션 프레임워크 란?

데이터 군을 저장하는 클래스들을 표준화한 설계

인터페이스 특징
List 순서가 있는 데이터 집합. 중복 허용
구현 클래스 : ArrayList, LinkedList, Stack, Vector
Set 순서가 없는 데이터 집합, 중복 허용하지 않음
구현 클래스 : HashSet, TreeSet 등
Map key와 value의 쌍으로 이뤄진 집합. 순서가 없고, key는 중복 허용하지 않고, value는 중복을 허용한다.
구현 클래스 : HashMap, TreeMap, Hashtable 등

 

a-1. Collection 인터페이스 메서드

메서드 설명
boolean add(Object o)
boolean addAll(Collection c)
객체나 콜렉션에 담긴 객체들을 콜렉션에 추가
void clear() 콜렉션의 모든 객체 삭제
boolean contains(Object o)
boolean containsAll(Collection c)
객체 혹은 콜렉션에 담긴 객체들이 콜렉션에 포함되어 있는지 참거짓
boolean equals(Object o) 동일한 Collection인지 참거짓
int hashCode() Collection의 해쉬코드를 반환
boolean isEmpty() Collection이 비어있는지 참거짓
Iterator iterator() Collection의 iterator를 반환
boolean remove(Object o) 지정된 객체를 삭제
boolean removeAll(Collection c) 콜렉션에 포함된 객체를 모두 삭제
boolean retainAll(Collection c) c에 포함된 객체만 남기고 모두 지운다.
콜렉션에 변화가 생기면 true를 반환
int size() 컬렉션에 저장된 객체 갯수 반환
Object[] toArray() 컬렉션에 저장된 객체를 객체배열로 반환
Object[] toArray(Object[] a) a에 콜렉션 객체를 저장

a-2. Collections 메소드

주의할 점음 java.util.Collection은 인터페이스이고 java.util.Collections는 클래스다. 둘을 혼동하지 말라.

fill(), copy(), sort(), binarySearch()등이 있다.

 

컬렉션의 동기화

멀티스레드 환경에서 데이터 무결성을 유지하기 위해 공유되는 객체에 동기화

static Collection synchronizedCollection(Collection c)
static List synchronizedList(List list)
static Set synchronizedSet(Set s)
static Map synchronizedMap(Map m)
static SortedSet synchronizedSortedSet(SortedSet s)
static SortedMap synchronizedSortedMap(SortedMap m)

//사용법
List syncList = Collections.synchronizedList(new ArrayList());

변경 불가 컬렉션 & 싱글톤

저장된 데이터를 보호하기 위해 읽기전용 전환.
단 하나의 객체만을 저장하는 컬렉션 생산(싱글톤)

//변경 불가 메소드(List, Set, Map등 다양하게 사용)
static Collection unmodifiedCollection(Collection c)

//싱글톤 컬렉션 만들기(List, Set, Map)
static List singletonList(Object o)
static Set singletonSet(Object o) //singletonSet이 아님에 주의

b. List<E> 인터페이스

Vector, Stack, ArrayList, LinkedList

나란히 저장한다.

중복 저장을 허용한다.

--ArrayList<E> 클래스: 배열을 이용해 인스턴스 저장

--LinkedList<E> 클래스: 리스트를 구성해 인스턴스 저장

 

b-1. List 메소드

메서드 설명
void add(int index, Object element)
boolean addAll(int index, Collection c)
지정된 위치에 객체 혹은 컬렉션에 포함된 객체를 추가
Object get(int index) 지정된 위치의 객체를 반환
int indexOf(Object o) 지정된 객체의 인덱스 값을 반환(앞부터 찾아감)
int lastIndexOf(Object o) 지정된 객체의 인덱스 값을 반환(뒤부터 찾아감)
ListIterator listIterator()
ListIterator listIterator(int index)
List의 객체에 접근할 수 있는 ListIterator를 반환
Object remove(int index) 인덱스에 위치한 객체를 지우고 해당 객체를 반환
Object set(int index, Object element) 지정된 위치에 객체를 저장
void sort(Comparator c) 지정된 비교자로 List를 정렬
List subList(int fromindex, int toindex) 지정된 범위에 있는 객체를 리스트로 반환

c. ArrayList

데이터 저장순서 유지.

중복 허용

메서드 설명
ArrayList() #생성자
ArrayList(int capacity) #생성자
ArrayList(Collection c) #생성자
크기가 0인 어레이리스트 생성
초기용량을 갖는 어레이리스트 생성
주어진 컬렉션이 저장된 어레이리스트 생성
boolean add(Object o)
void add(int index, Object element)
맨뒤, 혹은 정한 인덱스에 요소를 추가한다.
boolean add(Collection c)
boolean add(int i, Collection c)
어레이리스트에 콜렉션의 객체들을 모두 추가(특정 위치에 추가 가능)
void clear() 모든 객체 삭제
Object clone() 어레이리스트를 복제함
Object get(int index) 인덱스에 해당하는 객체 반환
boolean contains(Object o) 해당 객체가 존재하는 지 확인
int indexOf(Object o) 해당 객체가 존재하는 인덱스를 반환
boolean isEmpty() 어레이리스트가 비엇는지 참거짓
Iterator iterator() 어레이리스트의 Iterator객체를 반환
Object remove(int index) 인덱스에 해당하는 객체 삭제
Object remove(Object o) 객체가 존재하면 해당 객체 삭제
int size() 객체 갯수 반환
void sort(Comparator c) 정렬 기준대로 정렬
Object[] toArray() 저장된 모든 객체를 객체배열로 만듬
Object[] toArray(Object[] a) 저장된 모든 객체를 a에 저장해 반환

어레이리스트 인스턴스를 리스트 메소드로 이용한 예시

import java.util.ArrayList;
import java.util.List;

public class ListPractice {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();//컬렉션 인스턴스 생성
        
        list.add("Toy");
        list.add("Box");
        list.add("Robot");
        
        for(int i=0; i<list.size();i++) {
            System.out.println(list.get(i)+"\t");
        }
        System.out.println();
        
        list.remove(0);
        for(int i=0; i<list.size();i++) {
            System.out.println(list.get(i)+"\t");
        }
        System.out.println();
    }
}

d. LinkedList

장점 단점
데이터 삭제 추가가 빠름 데이터가 많을수록 접근성이 떨어짐

링크드리스트 인스턴스를 리스트 메소드로 이용한 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
 
public class ListPractice {
    public static void main(String[] args) {
        List<String> list = new LinkedList<>();//컬렉션 인스턴스 생성
        
        list.add("Toy");
        list.add("Box");
        list.add("Robot");
        
        for(int i=0; i<list.size();i++) {
            System.out.println(list.get(i)+"\t");
        }
        System.out.println();
        
        list.remove(0);
        for(int i=0; i<list.size();i++) {
            System.out.println(list.get(i)+"\t");
        }
        System.out.println();
        
    }
}
 
cs

-메소드는 ArrayList와 비슷
-두 예시의 차이는 인스턴스의 차이

-이 차이로 인해 같은 메소드를 사용해도 정보의 저장과 삭제 방식이 달라짐.

 

#enhanced for문 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.LinkedList;
import java.util.List;
 
public class ListPractice {
    public static void main(String[] args) {
        List<String> list = new LinkedList<>();//컬렉션 인스턴스 생성
        
        list.add("Toy");
        list.add("Box");
        list.add("Robot");
        
        for (String s : list) {
            System.out.println(s+"\t");
        }
        
    }
}
cs

--for each문을 사용할 수 있는 이유? Iterable<T> 인터페이스의 구현 덕분.

--collection<T>는 extends Iterable<T> 이기 때문에 다양한 자료구조로 부터 일정하게 참조 할 수 있는 것.

 

e. Stack

마지막 저장한 데이터가 먼저 나온다. (LIFO)

스택은 ArrayList와 같은 배열기반 클래스가 적합.

Stack<Integer> st = new Stack<>();
메서드 설명
boolean empty() 스택이 비었는지 확인
Object peek() 스택의 최상단 객체를 반환
(객체를 스택에서 빼지는 않음)
Object pop() 맨 위 저장된 객체를 꺼내서 반환
Object push(Object item) 스택에 객체 저장
int search(Object o) 스택에 객체 위치를 찾아 반환
(없으면 -1, 스택위치는 인덱스와 달리 1부터 시작)

f. Queue

먼저 저장한 데이터가 먼저 나온다. (FIFO)

큐는 LinkedList 클래스가 구현에 적절

Queue<Integer> q = new LinkedList<>();
메서드 설명
boolean add(Object o) 큐에 저장. 성공하면 true 반환
Object remove() 큐에서 객체를 꺼내 반환. 비어있으면 예외발생
Object element() 삭제없이 요소 읽어옴(스택의 peek과 달리 없으면 예외발생)
boolean offer(Object o) 큐에 객체 저장. 성공하면 true, 실패시 false
Object poll() 큐에서 객체를 꺼내서 반환, 비어있으면 null반환
Object peek() 삭제없이 요소 읽어옴(비어있으면 null)

-반복자

--Iterable<T> 인터페이스 안에 있는 Interator<T> interator(); 인스턴스를 반복자라 부름

--반복자는 상대가 누구든 간에 자료를 쉽게 파악함

--next(), hasNext(), remove() 메소드가 있음.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.LinkedList;
import java.util.List;
import java.util.Iterator;
public class ListPractice {
    public static void main(String[] args) {
        List<String> list = new LinkedList<>();//컬렉션 인스턴스 생성
        list.add("Toy");
        list.add("Box");
        list.add("Robot");
 
        Iterator<String> itr = list.iterator();
        while(itr.hasNext()) {
            String str=itr.next();
            System.out.println(str+"\t");
        }
        
    }
}
 

이때 반복자는 가장 맨 처음에 첫번째 인자를 가리키는게 아닌, 첫번째 인자 앞을 가르킨다고 이해하자.

remove는 현재 가르키는 대상을 삭제하고, next는 다음 대상을 참조.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
public class ListPractice {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("Toy""Box","Robot");
        //add 메소드 없이 이렇게 초기화 할 수 있지만, immutable의 단점이 있다.
        
        list=new ArrayList<>(list);
        //이렇게 하면 참조만 가능..?
    }
}



-배열 기반 리스트와 연결 기반 리스트 전환

--list = new  LinkedList<>(list);

--list = new ArrayList<>(list);

 

-List만 갖는 양방향 반복자

--public ListIterator<E> listIterator()

--Iterator<E>를 상속, 더 많은 기능 제공

--next(), hasNext(), remove()

--previous,hasPrevious()

--add()인스턴스 추가, set()인스턴스 변경

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.util.List;
import java.util.ListIterator;
import java.util.ArrayList;
import java.util.Arrays;
public class ListPractice {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("Toy""Box","Robot");
        list=new ArrayList<>(list);
        
        ListIterator<String> litr = list.listIterator();//양방향 반복자 획득
        String str;
        while(litr.hasNext()) {
            str=litr.next();
            System.out.print(str+'\t');
            if(str.equals("Toy")) {
                litr.add("Toy2");
            }
        }
        System.out.println();
        
        while(litr.hasPrevious()) {
            str=litr.previous();
            System.out.print(str+'\t');
            if(str.equals("Robot")) {
                litr.add("Robot2");
            }
        }
    }
}
 
 

양방향 반복자의 예