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<String> list = new ArrayList<>();
list.add("아구몬");
list.add("가루루몬");
list.add("아구몬"); // 중복 허용
System.out.println(list); // [아구몬, 가루루몬, 아구몬]
내부적으로 배열로 구현되어 있다.
List<String> list = new ArrayList<>();
내부 배열: [ "아구몬" | "가루루몬" | "그레이몬" | null | null ]
인덱스: 0 1 2
내부적으로 이중 연결 리스트로 구현되어 있다.
List<String> list = new LinkedList<>();
[아구몬] ↔ [가루루몬] ↔ [그레이몬]
각 노드가 이전/다음 노드의 참조를 가지고 있다.
| ArrayList | LinkedList | |
|---|---|---|
| 조회 | 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()); // 내림차순
// 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(...)) | 초기값 복사, 가변 리스트 |
| 인터페이스 타입으로 선언 | 구현체 교체 시 선언부 수정 불필요 |