List 컬렉션

Sunny·2023년 1월 11일
0

🌱 List 컬렉션

List 컬렉션 : ArrayList, Vector, LinkedList

List 컬렉션은 다음과 같은 특징이 있다.

  • 객체를 일렬로 늘어놓은 구조
  • 인덱스로 관리하기 때문에 객체를 저장하면 자동 인덱스가 부여
  • 인덱스로 객체를 검색, 삭제할 수 있는 기능 제공
  • 객체 자체를 저장하는 것이 아니라, 객체의 번지를 참조
  • 동일한 객체를 중복 저장 가능 (이 경우, 동일한 번지가 참조)
  • null 저장 가능 (이 경우, 해당 인덱스는 객체를 참조하지 않음)

다음은 List 컬렉션에서 공통적으로 사용 가능한 List 인터페이스의 메소드들이다.

기능메소드설명
객체 추가boolean add(E e)주어진 객체를 맨 끝에 추가
void add(int index, E element)주어진 인덱스에 객체를 추가
set(int index, E element)주어진 인덱스에 저장된 객체를 주어진 객체로 바꿈
객체 검색boolean contains(Object o)주어진 객체가 저장되어 있는지 여부
E get(int index)주어진 인덱스에 저장된 객체를 리턴
isEmpty()컬렉션이 비어있는지 조사
int size()저장되어 있는 전체 객체 수를 리턴
객체 삭제void clear()저장된 모든 객체를 삭제
E remove(int index)주어진 인덱스에 저장된 객체를 삭제
boolean remove(Object o)주어진 객체를 삭제

다음은 list 컬렉션의 사용 예시이다.

List<String> list = ...;
list.add("홍길동"); 		// 맨끝에 객체 추가
list.add(1, "홍길동2"); 	// 지정된 인덱스에 객체 삽입

String str = list.get(1); // 인덱스로 객체 찾기

list.remove(0); 		  // 인덱스로 객체 삭제
list.remove("홍길동2");     // 객체 삭제

// 전체 객체를 대상으로 하나씩 반복해서 저장된 객체 얻기
List<String> list = ...;
for(int i=0; i<list.size(); i++) {
	String str = list.get(i);
}

// 인덱스 번호가 없다면 향상된 for문을 이용하는 것이 편리
// 저장된 총 객체 수만큼 루핑
for(String str : list) { ... }

🌱 ArrayList

ArrayList는 List 인터페이스의 구현 클래스로, ArrayList에 객체를 추가하면 객체가 인덱스로 관리된다. 일반 배열과 같이 인덱스로 객체를 관리한다는 점에서는 유사하지만, 차이점이 있다. 일반 배열은 크기가 고정되고 사용 중에 크기를 변경할 수 없지만, ArrayList는 저장 용량(capacity)을 초과한 객체들이 들어오면 자동적으로 저장 용량이 늘어난다.

다음은 ArrayList 객체의 내부 구조이다.

ArrayList를 생성하기 위해서는 저장할 객체 타입을 타입 파라미터로 표기하고 기본 생성자를 호출하면 된다. 예시는 다음과 같다.

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

기본 생성자로 ArrayList 객체를 생성하면 내부에 10개의 객체를 저장할 수 있는 초기 용량(capacity)를 가지게 된다. 저장하는 객체 수가 늘어나면 용량이 자동으로 증가하지만, 처음부터 용량을 크게 잡고 싶다면 용량의 크기를 매개값으로 받는 생성자를 이용하면 된다.

List<String> list = new ArrayList<String>(30);

ArrayList에 객체를 추가하면 인덱스 0부터 차례대로 저장된다. ArrayList에서 특정 인덱스의 객체를 제거하면 바로 뒤 인덱스부터 마지막 인덱스까지 모두 앞으로 1씩 당겨진다. 마찬가지로 특정 인덱스에 객체를 삽입하면 해당 인덱스부터 마지막 인덱스까지 모두 1씩 밀려난다.

따라서 빈번한 객체 삭제와 삽입이 일어나는 곳에서는 ArrayList를 사용하는 것이 바람직하지 않다. 그 경우에는 LinkedList를 사용하는 것이 좋다. 그러나 인덱스 검색이나, 맨 마지막에 객체를 추가하는 경우에는 ArrayList가 더 좋은 성능을 발휘한다.


🌱 Vector

Vector는 ArrayList와 동일한 내부 구조를 가지고 있다.

Vector를 생성하기 위해서는 저장할 객체 타입을 타입 파라미터로 표기하고 기본 생성자를 호출하면 된다.

List<E> list = new Vector<E>();

ArrayList와 다른 점은 Vector은 동기화된 메소드로 구성되어 있기 때문에 멀티 스레드가 동시에 이 메소드들을 실행할 수 없고, 하나의 스레드가 실행을 완료해야만 다른 스레드를 실행할 수 있다. 그래서 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제 할 수 있다. 이것을 스레드가 안전하다(Thread Safe)라고 말한다.

다음은 사용 예시이다.

import java.util.*;

public class Ex{
	public static void main(String[] args) {
    	List<Board> list = new Vector<Board>();
        
        // Board 객체를 저장
        list.add(new Board("제목1","내용1","글쓴이1"));
        list.add(new Board("제목2","내용2","글쓴이2"));
        list.add(new Board("제목3","내용3","글쓴이3"));
        list.add(new Board("제목4","내용4","글쓴이4"));
        list.add(new Board("제목5","내용5","글쓴이5"));
 
 		// 삭제
        list.remove(2); // 2번 인덱스 객체 삭제(제목3, 뒤의 인덱스는 1씩 앞으로 당겨짐)
        list.remove(3); // 3번 인덱스 객체 삭제(제목5)
        
        for(int i=0; i<list.size(); i++) {
        	Board board = list.get(i);
            System.out.println(board.subject+"\t"+board.content+"\t"+board.writer);
        }
 	}
}

// 게시물 정보 객체
public class Board {
	String subject;
    String content;
    String writer;
    
    public Board(String subject, String content, String writer) {
    	this.subject = subject;
        this.content = content;
        this.writer = writer;    
    }
}

🌱 LinkedList

LinkedList는 List의 구현 클래스이므로 ArrayList와 사용 방법은 똑같지만 내부 구조는 완전히 다르다. ArrayList는 내부 배열에 객체를 저장해서 인덱스로 관리하지만, LinkedList는 인접 참조를 링크해서 체인처럼 관리한다.

LinkedList에서 특정 인덱스의 객체를 제거하면 앞뒤 링크만 변경되고 나머지 링크는 변경되지 않는다. 특정 인덱스에 객체를 삽입할 때도 마찬가지다.

다음은 중간에 객체를 제거할 경우 앞뒤 링크의 수정이 일어나는 모습을 보여주고 있다.

LinkedList를 생성하기 위해서는 저장할 객체 타입을 타입 파라미터(E)에 표기하고 기본 생성자를 호출하면 된다. LinkedList가 처음 생성될 때에는 어떠한 링크도 만들어지지 않기 때문에 내부는 비어 있다고 보면 된다.

List<E> list = new LinkedList<E>();
profile
개발에 재미를 붙여보기 :)

0개의 댓글