List<E> 인터페이스
List<E> 인터페이스를 구현하는 대표적인 컬렉션 클래스 둘은 다음과 같다.
- ArrayList<E> 배열 기반 자료구조, 배열을 이용하여 인스턴스 저장
- LinkedList<E> 리스트 기반 자료구조, 리스트를 이용하여 인스턴스 저장
List<E> 인터페이스를 구현하는 컬렉션 클래스들의 공통 특성
- 인스턴스의 저장 순서 유지
- 동일 인스턴스의 중복 저장을 허용한다.
배열 기반의 장단점
배열은 크기가 고정되어 있어서 만약 원소를 추가하고 싶으면 사이즈가 큰 배열을 새로 만들고 기존의 배열의 원소를 차례대로 옮겨준 다음 원소를 추가해줘야 함! 기존 배열 삭제도 해야됨!
리스트는 그냥 추가하면 됨
단순저장은 배열은 그냥 저장하면 되지만 리스트는 선으로 연결 해줘야 되서 더 느림!
ArrayList<E> 클래스
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.print(list.get(i) + '\t');
System.out.println();
list.remove(0); // 첫 번째 인스턴스 삭제
// 첫 번째 인스턴스 삭제 후 나머지 인스턴스들을 참조
for (int i = 0; i< list.size(); i++)
System.out.print(list.get(i) + '\t');
System.out.println();
}
배열 기반 자료구조이지만 공간의 확보 및 확장은 ArrayList 인스턴스가 스스로 처리한다.
LinkedList<E> 클래스
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.print(list.get(i) + '\t');
System.out.println();
list.remove(0); // 첫 번째 인스턴스 삭제
// 첫 번째 인스턴스 삭제 후 나머지 인스턴스들을 참조
for(int i = 0; i < list.size(); i++)
System.out.print(list.get(i) + '\t');
System.out.println();
}
리스트 기반 자료구조는 열차 칸을 더하고 빼는 형태의 자료구조이다.
- 인스턴스 저장 열차 칸을 하나 더한다.
- 인스턴스 삭제 해당 열차 칸을 삭제한다.
ArrayList<E> vs LinkedList<E>
ArrayList<E>의 단점
- 저장 공간을 늘리는 과정에서 시간이 비교적 많이 소요된다.
- 인스턴스의 삭제 과정에서 많은 연산이 필요할 수 있다. 따라서 느릴 수 있다.
ArrayList<E>의 장점
- 저장된 인스턴스의 참조가 빠르다.
LinkedList<E>의 단점
- 저장된 인스턴스의 참조 과정이 배열에 비해 복잡하다. 따라서 느릴 수 있다.
LinkedList<E>의 장점
- 저장 공간을 늘리는 과정이 간단하다.
- 저장된 인스턴스의 삭제 과정이 단순하다.
저장된 인스턴스의 순차적 접근 방법 1 : enhanced for 문의 사용
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.print(s + '\t');
. . . .
}
for-each 문의 대상이 되기 위한 조건
Iterable<T> 인터페이스의 구현
for-each문은 반복자 기반의 반복문으로 바뀜!!
public interface Collection<E> extends Iterable<E>
저장된 인스턴스의 순차적 접근 방법 2
public static void main(String[] args) {
List<String> list = new LinkedList<>();
. . . .
Iterator<String> itr = list.iterator(); // 반복자 획득, itr이 지팡이를 참조한다.
, , , ,
// 반복자를 이용한 순차적 참조
while( itr.hasNext() ) { // next 메소드가 반환할 대상이 있다면,
str = itr.next(); // next 메소드를 호출한다.
. . . .
}
}
public interface Iterable<T> {
Iterator<T> iterator();
. . . .
}
Iterator 반복자의 세 가지 메소드
E next() 다음 인스턴스의 참조 값을 반환
boolean hasNext() next 메소드 호출 시 참조 값 반환 가능 여부 확인
void remove() next 메소드 호출을 통해 반환했던 인스턴스 삭제
// 반복자를 이용한 참조 과정 중 인스턴스의 삭제
while(itr.hasNext()) {
str = itr.next();
if(str.equals("Box"))
itr.remove(); // 위에서 next 메소드가 반환한 인스턴스 삭제
}
배열보다는 컬렉션 인스턴스가 좋다. : 컬렉션 변환
다음 두 가지 이유로 배열보다 ArrayList<E>가 더 좋다.
인스턴스의 저장과 삭제가 편하다.
반복자를 쓸 수 있다.
단, 배열처럼 선언과 동시에 초기화가 불가능하다. 그러나 다음 방법을 쓸 수 있다.
List<String> list = Arrays.asList("Toy", "Robot", "Box");
-> 인자로 전달된 인스턴스들을 저장한 컬렉션 인스턴스의 생성 및 반환
-> 이렇게 생성된 리스트 인스턴스는 Immutable 인스턴스이다. - 참조만 가능, 수정,삭제 안됨!!
다음 생성자를 통해서 새로운 ArrayList 인스턴스 생성 가능
public ArrayList(Collection<? extends E> c) { . . . }
-> Collection<E>를 구현한 컬렉션 인스턴스를 인자로 전달받는다.
-> 그리고 E는 인스턴스 생성 과정에서 결정되므로 무엇이든 될 수 있다.
-> 덧붙여서 매개변수 c로 전달된 컬렉션 인스턴스에서는 참조만(꺼내기만) 가능하다. - 안정적으로 복사하기 위한 것임!!
public static void main(String[] args) {
List<String> list = Arrays.asList("Toy", "Box", "Robot", "Box"); - 어차피 꺼내기만 가능!!
// 생성자 Public ArrayList(Collection<? extends E> c)를 통한 인스턴스 생성
list = new ArrayList<>(list);
. . . .
}
대다수 컬렉션 클래스들은 다른 컬렉션 인스턴스를 인자로 전달받는 생성자를 가지고 있어서,
다른 컬렉션 인스턴스에 저장된 데이터를 복사해서 새로운 컬렉션 인스턴스를 생성할 수 있다.
배열 기반 리스트를 연결 기반 리스트로...
public ArrayList(Collection<? extends E> c) // ArrayList<E> 생성자 중 하나
-> 인자로 전달된 컬렉션 인스턴스로부터 ArrayList<E> 인스턴스 생성
public LinkedList(Collection<? extends E> c) // LinkedList<E> 생성자 중 하나
-> 인자로 전달된 인스턴스로부터 LinkedList<E> 인스턴스 생성
public static void main(String[] args) {
List<String> list = Arrays.asList("Toy", "Box", "Robot", "Box");
list = new ArrayList<>(list);
. . .
// ArrayList<E> 인스턴스 기반으로 LinkedList<E> 인스턴스 생성
list = new LinkedList<>(list);
. . .
}
기본 자료형 데이터의 저장과 참조
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
list.add(10); // 저장 과정에서 오토 박싱 진행
list.add(20);
list.add(30);
오토 박싱과 오토 언박싱 덕분에 컬렉션 인스턴스에 기본 자료형의 값도 저장 가능하다.
int n;
for(Iterator<Integer> itr = list.iterator(); itr.hasNext(); ) {
n = itr.next(); // 오토 언박싱 진행
System.out.print(n + "\t");
}
System.out.println();
}
리스트만 갖는 양방향 반복자
public ListIterator<E> listIterator() // List<E> 인터페이스의 메소드
-> ListIterator<E>는 Iterator<E>을 상속한다.
E next() 다음 인스턴스의 참조 값을 반환
boolean hasNext() next 메소드 호출 시 참조 값 반환 가능 여부 확인
void remove() next 메소드 호출을 통해 반환했던 인스턴스를 삭제
E previous() next 메소드와 기능은 같고 방향만 반대
boolean hasPrevious() hasNext 메소드와 기능은 같고 방향만 반대
void add(E e) 인스턴스의 추가
void set(E e) 인스턴스의 변경
양방향 반복자의 예
public static void main(String[] args) {
List<String> list = Arrays.asList("Toy", "Box", "Robot", "Box");
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")) // "Toy" 만나면 "Toy2" 저장
litr.add("Toy2");
}
System.out.println();
while(litr.hasPrevious()) { // 오른쪽에서 왼쪽으로 이동을 위한 반복문
str = litr.previous();
System.out.print(str + '\t');
if(str.equals("Robot")) // " Robot" 만나면 "Robot2" 저장
litr.add("Robot2");
}
. . . .
}
'# 02 > Java' 카테고리의 다른 글
[윤성우 열혈자바] 23-4. Queue<E> 인터페이스를 구현하는 컬렉션 클래스들 (0) | 2019.10.24 |
---|---|
[윤성우 열혈자바] 23-3. Set<E> 인터페이스를 구현하는 컬렉션 클래스들 (0) | 2019.10.24 |
[윤성우 열혈자바] 23-1. 컬렉션 프레임워크의 이해 (0) | 2019.10.24 |
[윤성우 열혈자바] 22-1. 제네릭의 심화 문법 (0) | 2019.10.23 |
[윤성우 열혈자바] 21-2. 제네릭의 기본 문법 (0) | 2019.10.23 |