[TIL] Java 컬렉션 — List

revo·2026년 4월 14일

자바

목록 보기
25/30
post-thumbnail

컬렉션 프레임워크 구조

java.util.Collection (인터페이스)
├── List   (인터페이스)
│   ├── ArrayList
│   ├── LinkedList
│   └── Vector

Collection은 최상위 인터페이스다. List, Set, Queue가 이걸 상속받는다.

인터페이스끼리는 extends를 쓴다. implements는 클래스가 인터페이스를 구현할 때만 쓴다.

public interface List<E> extends Collection<E> { }  // 인터페이스 → 인터페이스
public class ArrayList<E> implements List<E> { }    // 클래스 → 인터페이스

List란

순서가 있고, 중복을 허용하는 컬렉션.

배열과 비슷하지만 크기가 동적으로 변한다.

List<String> list = new ArrayList<>();
list.add("아구몬");
list.add("가루루몬");
list.add("아구몬"); // 중복 허용
System.out.println(list); // [아구몬, 가루루몬, 아구몬]

주요 구현체 — ArrayList vs LinkedList

ArrayList

내부적으로 배열로 구현되어 있다.

List<String> list = new ArrayList<>();
내부 배열: [ "아구몬" | "가루루몬" | "그레이몬" | null | null ]
인덱스:         0          1           2
  • 조회 O(1) → 인덱스로 바로 접근
  • 중간 삽입/삭제 O(n) → 뒤 요소를 전부 밀어야 함
  • 맨 끝 삽입 O(1) → 밀 필요 없음

LinkedList

내부적으로 이중 연결 리스트로 구현되어 있다.

List<String> list = new LinkedList<>();
[아구몬] ↔ [가루루몬] ↔ [그레이몬]

각 노드가 이전/다음 노드의 참조를 가지고 있다.

  • 조회 O(n) → 처음부터 순서대로 따라가야 함
  • 삽입/삭제 O(1) → 참조만 바꾸면 됨 (단, 해당 노드까지 찾아가는 건 O(n))

언제 뭘 쓰나

ArrayListLinkedList
조회O(1)O(n)
중간 삽입/삭제O(n)O(1)
맨 끝 삽입O(1)O(1)
메모리적음많음 (참조 2개 저장)

주요 메서드

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

// 추가
list.add("아구몬");           // 맨 끝에 추가
list.add(0, "가루루몬");      // 특정 인덱스에 추가

// 조회
String s = list.get(0);      // 인덱스로 조회
int size = list.size();       // 크기
boolean has = list.contains("아구몬"); // 포함 여부

// 수정
list.set(0, "그레이몬");      // 인덱스 위치 값 교체

// 삭제
list.remove(0);               // 인덱스로 삭제
list.remove("아구몬");        // 값으로 삭제 (제일 처음 만난 것만 삭제)

// 순회
for (String item : list) {
    System.out.println(item);
}

// 정렬
Collections.sort(list);                      // 오름차순
list.sort(Comparator.reverseOrder());        // 내림차순

List 선언 방식

// 1. 일반적인 방식
List<String> list = new ArrayList<>();

// 2. 초기값 포함 — 수정/삭제/추가 가능
List<String> list = new ArrayList<>(List.of("아구몬", "가루루몬"));

// 3. 불변 리스트 — 수정/삭제/추가 불가
List<String> list = List.of("아구몬", "가루루몬");
list.add("그레이몬"); // UnsupportedOperationException

new ArrayList<>(List.of(...))List.of(...) 의 차이

List.of()new ArrayList<>() 생성자 인자로 넘기면, ArrayList가 내부적으로 요소들을 복사해서 새로운 ArrayList를 만든다. List.of()는 초기값을 편하게 넘기는 용도로만 쓰인 것이고, 불변성은 사라진다.

List<String> list = new ArrayList<>(List.of("아구몬", "가루루몬"));
list.add("그레이몬");      // 가능
list.remove("아구몬");     // 가능
list.set(0, "워그레이몬"); // 가능

불변이 유지되는 건 List.of() 결과를 직접 변수에 담았을 때만이다.


ArrayList list가 아니라 List list로 선언하나

List<String> list = new ArrayList<>();     // 권장
ArrayList<String> list = new ArrayList<>(); // 비권장

다형성 때문이다. List 인터페이스 타입으로 선언하면 나중에 구현체를 바꿔도 선언부를 수정할 필요가 없다.

List<String> list = new LinkedList<>(); // ArrayList → LinkedList 교체, 선언부 그대로

정리

개념핵심
List순서 있음, 중복 허용, 동적 크기
ArrayList배열 기반, 조회 O(1), 중간 삽입/삭제 O(n)
LinkedList연결 리스트 기반, 조회 O(n), 삽입/삭제 O(1)
List.of()불변 리스트
new ArrayList<>(List.of(...))초기값 복사, 가변 리스트
인터페이스 타입으로 선언구현체 교체 시 선언부 수정 불필요

0개의 댓글