본문 바로가기

Java/문법

17 - 2장 List<E> 컬렉션 인터페이스

1. 배열과 리스트의 차이점

 

- 배열 = 저장공간의 크기가 고정적

 리스트 = 저장공간의 크기가 동적으로 변화

 

-배열의 특징

 -> 크기가 7인 문자열 배열 생성과 동시에 초기화 

 -> 2개의 데이터를 null값으로 바꾼이후에도 크기 7

String[] array = new String[] ["가","나","다","라","마","바","사"};
array[2] = null;
array[5] = null;
System.out.println(array.length); //7

 

- 리스트의 특징

-> 최초 리스트 객체를 생성하면 데이터가 없으므로 저장공간의 크기 0

-> 데이터 7개 추가하면 저장 공간의 크기=7

-> 2개의 데이터 삭제하면 리스트의 저장 공간 크기는 5로 줄어들고, 인덱스 번호 또한 그에 맞게 조정

-> 데이터의 저장 공간 크기(size) = 데이터의 수 

list<String> alist = new ArrayList<>();

alist.add("가");alist.add("나"); alist.add("다"); alist.add("라");
alist.add("마"); alist.add("바"); alist.add("사");

System.out.println(alist.size()); //7

alist.remove("다");
alist.remove("바");

System.out.println(alist.size()); //5

 

2. List<E> 객체 생성하기 

 

- List<E>는 인터페이스이기 때문에 객체를 스스로 생성불가 

 -> 객체를 생성하기 위해서  List<E>를 상속받아 자식 클래스를 생성하고, 생성한 자식 클래스를 이용해 객체 생성

 

-But, 컬렉션 프레임워크 이용시 직접 인터페이스 구현할 필요 x

 -> 컬렉션 프레임워크 안에 이미 각각의 특성 및 목적에 따른 클래스 구현돼 있음

 

-List<E> 인터페이스를 구현한 대표 클래스 

 ->ArrayList<E> , Vector<E>, LinkedList<E>

 

1) List<E> 인터페이스 구현 클래스 생성자로 동적 클래스 객체 생성

 

 - List<E>는 제네릭 인터페이스이므로 이를 상속한 자식 클래스들도 제네릭 클래스 

 - 객체를 생성할때 제네릭의 실제 타입을 지정해야함 

 - 기본생성자 사용

   -> 기본으로 10만큼의 저장 용량 내부에 확보

 - 초기 저장 용량(capacity)를 매개변수로 포함하고 있는 생성자 사용

   

// 다형적 표현에 따라 부모 타입인 List<E>타입으로 선언 가능
List<제네릭 타입 지정> 참조 변수 = new ArrayList<제네릭 타입지정>();
List<제네릭 타입 지정> 참조 변수 = new Vector<제네릭 타입지정>();
List<제네릭 타입 지정> 참조 변수 = new LinkedList<제네릭 타입지정>();

ArrayList<제네릭 타입 지정> 참조 변수 = new ArrayList<제네릭 타입지정>();
Vector<제네릭 타입 지정> 참조 변수 = new Vector<제네릭 타입지정>();
LinkedList<제네릭 타입 지정>참조 변수 = new LinkedList<제네릭 타입지정>();
List<Integer> aList1 = new ArrayList<Integer>(); //capacity =10
List<Integer> aList2 = new ArrayList<Integer>(30); //capacity =30
Vector<Integer>aList3 = new Vector<String>(); //capacity =10
List<MyWork> aList4 = new LinkedList<MyWork>(20); //오류 -> LInkedList는 capcity 지정불가

 

2) Arrays.asList() 메서드를 이용해 정적 컬렉션 객체 생성

 

- Arrays 클래스의 asList(T..) 정적 메서드를 사용

- 내부적으로 배열을 먼저 생성하고, 이를 List<E>로 래핑한 것

- 컬렉션 객체인데도 저장 공간의 크기를 변경 불가

- 데이터의 추가 (add()) 및 삭제(remove())불가 

- 저장공간의 크기를 변경하지 않는 데이터의 변경(set())은 가능

List<제네릭 타입 지정> 참조 변수 = Arrays.asList(제네릭 타입 저장 데이터);
List<Integer> aList1 = Arrays.asList(1,2,3,4);
aList1.set(1,7); //[1,7,3,4]
aList1.add(5); //오류
aList1.remove(0); //오류

 

3. List<E>의 주요 메서드 

 

구분 메서드명 기능
데이터 추가 add(E element) 매개변수로 입력된 원소를 리스트의 마지막에 추가
add(int index, E element) index 위치에 입력된 원소 추가
addAll(Collection<? Extends E> c) 매개변수로 입력된 컬렉션 전체를 마지막에 추가
addAll(int index, Collection<? Extends E> c) index 위치에 입력된 컬렉션 전체를 추가
데이터 변경 set(int index, E element) index 위치의 원솟값을 입력된 원소로 변경
데이터 삭제 remove(int index) index 위치의 원솟값 삭제
remove(Object o) 원소 중 매개변수 입력과 동일한 객체 삭제
clear() 전체 원소 삭제
리스트 데이터 정보추출 get(int index) index 위치의 원솟값을 꺼내 리턴
size() 리스트 객체 내의 포함된 원소의 개수
isEmpty() 리스트의 원소가 하나도 없는지 여부를 리턴
리스트 배열 변환 toArray() 리스트를 Obejct 배열로 변환
toArray(T[] t) 입력매개변수로 전달한 타입의 배열로 변환

- toArray

 -> 리스트를 원소의 자료형과 상관없이 Object[]로 변환

 -> 특정 타입으로 변환하기 위해서는 다운캐스팅 필요 

 

 -toArray(T[] t)

  ->특정 타입의 배열로 리턴받기 위해서 매개변수로 특정 타입의 배열 객체를 만들어 넘겨줌 

  ->list의 size() >= 배열의 length -> list의 크기를 지니고 있는 배열 생성

  ->list의 size() < 배열의 length -> 배열  length의 크기를 지니고 있는 배열 생성

 

4. ArrayList<E> 구현 클래스 

 

- List<E>가 지니고 있는 특징( 데이터를 인덱스로 관리, 저장공간을 동적으로 관리) 을 그대로 지님

 

- ArrayList<E>의 특징

 -> List<E> 인터페이스를 구현한 구현 클래스 

 -> 배열처럼 수집(Collect)한 원소(Element)를 인덱스(Index)로 관리하며 저장용량(Capacity)를 동적 관리

 

1) 데이터 추가하기 - add()

 

 -단일 데이터 추가

 - toString() -> 모든 컬렉션 구현 클래스는 이 메서드에서 모든 데이터를 한번에 정리해 출력하도록 오버라이딩 

                   -> 생략 가능

List<Integer>aList1 = new ArrayList<Integer>(); //list<integer> 객체 생성

//add(E element)
aList.add(3);
aList.add(4);
aList.add(5);
System.out.println(aList1.toString()); //[3,4,5]

//add(int index, E element)
aList.add(1,6);
System.out.println(aList1.toString()); //[3,6,4,5]

- 컬렉션 객체 추가 

 -> 컬렉션 객체를 통째로 입력매개변수로 받아 추가

//addAll(Colleciton<? extends E>c)
List<Integer>aList2 = new ArrayList<Integer>();
aList2.add(1);
aList2.add(2);
aList2.addAll(aLis1); // aList = [3,6,4,5]
System.out.println(aList2.toString()); //[1,2,3,6,4,5]

//addAll(int index, Collection<? extedns E> c)
List<Integer>aList3 = new ArrayList<Integer>();
aList3.add(1);
aList3.add(2);
aList3.addAll(1,aList3);
System.out.println(aList3.toString()); //[1,1,2,2]

 

2) 데이터 변경하기 -set()

 

-데이터의 변경

 -> set()메서드에서는 기존에 있는 데이터만 변경 가능

 -> 없는 인덱스 위치에 값을 대입하면 IndexOutOfBoundsException 발생

//set(int index, E element) : aList3=[1,1,2,2]
aList3.set(1,5);
aList3.set(3,6);
//aList3.set(4,7)l //IndexOutOfBoundsException
System.out.println(aList3.toString()); //[1,5,2,6]

 

3) 데이터 삭제하기 - remove(), clear()

 

- 데이터 삭제 

 -> remove(new Integer(2)) : 정숫값 2를 원소로 갖는 객체를 지워라 

 -> clear() : 데이터의 개수에 관계없이 모든 데이터를 한 번에 삭제 

//remove(int index) ;aList3=[1,5,2,6]
aList3.remove(1);
System.out.println(aList3.toString()); //[1,2,6]

//remove(Object o)
aList3.remove(new Integer(2));
System.out.println(aList3.toString()); //[1,6]

//clear()
aList3.clear();
System.out.println(aList3.toString()); //[}

 

4) 데이터 정보 추출하기 - isEmpty(), size(), get(int index)

 

- 데이터 정보 추출

 ->isEmpty() :데이터의 존재 여부, 데이터 x -> true 리턴

 ->size() : 저장 데이터의 개수 

 ->get(int index) : 특정위치의 데이터값 가져오기

//isEmpty() aList3=[]
System.out.println(aList3.isEmpty()); //true

/size()
aList3.add(1);
aList3.add(2);
aList3.add(3);
System.out.println(aList3.toString()); //[1,2,3]
System.out.println("size: " +aList3.size()); //size:3

//get(int index)
System.out.println("0번째:" + aList3.get(0)); //0번째:1
System.out.println("1번째:" + aList3.get(1)); //1번째:2
System.out.println("2번째:" + aList3.get(2)); //2번째:3
for(int i=0; i< aList3.size(); i++) {
	System.out.println("i번째:" +aList3.get(i));
}

 

5) 배열로 변환하기 - toArray(), toArray(T[] t)

 

//toArray() aList3 =[1,2,3]
Object[] object =aList3.toArray();
System.out.println(Array.toString(Object)); //[1,2,3]

//toArray(T[]t)
Integer[] integer1 = aList3.toArray(new Integer[0]);
System.out.println(Array.toString(Integer1)); //[1,2,3]

//toArray(T[]t)
Integer[] integer2 = aList3.toArray(new Integer[5]);
System.out.println(Array.toString(Integer2)); //[1,2,3,null,null]

 

5. Vector<E> 구현 클래스 

 

import java.utill.Vector;

List<Integer>vector1 = new Vector<Integer>();

- List<E>의 공통 특징(동일 타입 수집, 메모리 동적 할당, 데이터 추가/변경/삭제 메서드) 지님

 

- 동기화 메서드(synchronized method)로 구현돼 있으므로 멀티 쓰레드에 적합하도록 설계

 동기화 메서드 

 => 하나의 공유 객체를 2개의 쓰레드가 동시에 사용할 수 없도록 만든 메서드 

 

- 자바 API에 포함된 Vector<E>클래스

public synchronized E remove(int index) {
	//...
}
public synchronized E get(int index) {
	//...
}

-싱글 쓰레드에서는 ArrayList<E>를 쓰는 것이 효율적

 

6. LinkedList<E> 구현 클래스 

 

import.java.util.LinkedList;

List<Integer>LinkedList = new LinkedList<Integer>();

- List<E>의 공통 특징(동일 타입 수집, 메모리 동적 할당, 데이터 추가/변경/삭제 메서드) 지님

- 싱글 쓰레드에서 사용하기 적합( 동기화 x)

- ArrayList<E>와의 차이점

  

1) LinkedList<E>는 저장용량을 매개변수로 갖는 생성자가 없기 때문에 객체를 생성할 때 저장용량 지정 불가 

List<E> aLinkedList1 = new LinkedList<Integer>(); //o
List<E> aLinkedList1 = new LinkedList<Integer>(20); //x

 

2) 내부적으로 데이터를 저장하는 방식이 서로 다름

ArrayList<E> 모든 데이터를 위치 정보(인덱스)와 값으로 저장
LinkedList<E> 앞뒤 객체의 정보를 저장
모든 데이터가 서로 연결된 형태로 관리 
데이터가 연속된 위치에 저장 x
데이터 부분과 주소 부분을 별도로 가지고 있음

 

7. ArrayList<E>와 LinkedList<E>의 성능 비교 

 

구분 ArrayList<E> LInkedList<E>
추가, 삭제(add,remove) 속도 느림 속도 빠름
검색(get) 속도 빠름  속도 느림

- ArrayList<E> 데이터 추가

 -> ArrayList<E>에서 데이터를 추가하면 다른 데이터는 한칸씩 뒤로 밀려남

 -> 밀려나는 모든 데이터의 위치 정보를 수정해야 한다는 것을 의미 

 

- LinkedList<E> 데이터 추가

 -> LinkedList<E>는 각 원소의 앞 뒤 객체 정보만을 저장하고 있으므로 어딘가에 값이 추가되면

 값이 추가된 위치의 앞뒤 데이터 정보만 수정하면됨

 

-ArrayList<E> 데이터 검색

 -> 데이터 자체가 인덱스 번호를 갖고 있으므로 특정 인덱스 위치의 데이터를 빠르게 찾을 수 있음

 

- LInkedList<E> 데이터 검색

 -> 각 원소가 자신의 인덱스 정보를 따로 갖고 있지 않음

 -> 앞에서부터 차례대로 번호를 세어가면서 인덱스의 위치를 찾아야함

 

-ArrayList<E>와 LinkedList<E>의 성능 비교 

 -> System.nanoTime() : 시작과 끝 시점을 측정해 그 차잇값을 나노초 단위로 읽음으로써 실행시간 계산 

 -> 중간 위치에 데이터를 추가 또는 삭제할 일이 많을 때는 LinkedList<E>

    데이터를 검색할 일이 많을 때는 ArrayList<E> 사용이 효율적

 

package CollectionFramework;

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

public class Collection1 {
	public static void main(String[] args) {
		//1.데이터 추가 시간 비교
		List<Integer>aList = new ArrayList<>();
		List<Integer>LinkedList = new LinkedList<>();
		long startTime =0, endTime = 0;
		
		//1.1 ArrayList 데이터 추가 시간
		startTime = System.nanoTime();
		for(int i=0; i <100000; i++) {
			aList.add(0,i);
		}
		endTime = System.nanoTime();
		System.out.println("ArrayList 데이터 추가 시간="+(endTime - startTime)+"ns");
		
		//1.2 LinkedList 데이터 추가 시간
		startTime = System.nanoTime();
		for(int i=0; i <100000; i++) {
			LinkedList.add(0,i);
		}
		endTime = System.nanoTime();
		System.out.println("LinkedList 데이터 추가 시간="+(endTime - startTime)+"ns");
		
		//2-1 ArrayList 데이터 검색 시간
		startTime = System.nanoTime();
		for(int i=0; i <100000; i++) {
			aList.get(i);
		}
		endTime = System.nanoTime();
		System.out.println("ArrayList 데이터 검색 시간="+(endTime - startTime)+"ns");
		
		//2-2 LinkedList 데이터 검색 시간
		startTime = System.nanoTime();
		for(int i=0; i <100000; i++) {
			LinkedList.get(i);
		}
		endTime = System.nanoTime();
		System.out.println("LinkedList 데이터 검색 시간="+(endTime - startTime)+"ns");
		
		//3-1 ArrayList 데이터 삭제 시간
		startTime = System.nanoTime();
		for(int i=0; i <100000; i++) {
			aList.remove(0);
		}
		endTime = System.nanoTime();
		System.out.println("ArrayList 데이터 삭제 시간="+(endTime - startTime)+"ns");
		
		//3-2 LinkedList 데이터 삭제 시간
		startTime = System.nanoTime();
		for(int i=0; i <100000; i++) {
			LinkedList.remove(0);
		}
		endTime = System.nanoTime();
		System.out.println("LinkedList 데이터 삭제 시간="+(endTime - startTime)+"ns");
	}
}