2주차 Unit 5.1 — List / Set / Map의 본질적 차이

Psj·2026년 5월 18일

F-lab

목록 보기
69/230

Unit 5.1 — List / Set / Map의 본질적 차이

F-LAB JAVA · 2주차 · Phase 5 · 컬렉션 프레임워크 내부 구조
🚀 Phase 5 시작 — 코드 실무 직결의 컬렉션 내부 들여다보기


📌 학습 목표

이 Unit을 끝내면 다음을 답할 수 있어야 한다.

  • List · Set · Map의 본질적 의미 차이는?
  • "순서가 있다"는 삽입 순서와 정렬 순서 중 어느 것인가?
  • HashSet이 어떻게 중복을 막는가?
  • Collection 인터페이스 계층의 전체 그림은?
  • Map은 왜 Collection의 자식이 아닌가?
  • 각 자료구조의 시간 복잡도가 자료구조 선택을 어떻게 좌우하나?
  • ILIC에서 자료구조를 잘못 선택했을 때의 실제 사고는?

🎯 핵심 한 문장

List, Set, Map은 "데이터 보관 방식"의 3가지 추상화다.
List = "순서가 있는 컬렉션", Set = "중복 없는 컬렉션", Map = "키-값 짝".
같은 데이터라도 어느 추상화를 선택하느냐에 따라 메모리 구조, 시간 복잡도, 의도가 모두 달라진다.
Phase 5의 출발점.

비유 — 정리함의 3가지 스타일

자료구조비유
List선반에 책을 순서대로 놓음 (인덱스로 찾기)
Set우표 컬렉션 (중복 없음, 순서 무관)
Map전화번호부 (이름 → 번호 매핑)

같은 "정보 보관"이지만 목적이 다름.
선택을 잘못하면 코드도 비효율도 따라옴.


🧭 9개 섹션 로드맵

1. 컬렉션 프레임워크의 큰 그림
2. List — "순서 있는 컬렉션"
3. Set — "중복 없는 컬렉션"
4. Map — "키-값 매핑"
5. 시간 복잡도 비교
6. Map이 Collection의 자식이 아닌 이유
7. ILIC 실무 — 자료구조 선택 가이드
8. 흔한 실수 + 잘못된 선택의 사고
9. 면접 질문 + 자기 점검

1️⃣ 컬렉션 프레임워크의 큰 그림

1.1 1주차 복습

박승제씨가 1주차 Phase 6에서 본 것:

1주차 컬렉션 학습:
  - ArrayList vs LinkedList 비교
  - HashMap의 내부 동작 (PPT까지)
  - 자료구조 선택 기준 개요

각 자료구조를 따로 봤음.

1.2 2주차 Phase 5의 깊이

Phase 5의 차이:
  - 자료구조 간 관계 (인터페이스 계층)
  - 내부 메모리 구조 정밀
  - 배열 확장 정책 코드로 검증
  - 시간 복잡도의 진짜 의미
  - 자료구조 잘못 선택 시 실제 사고

1.3 인터페이스 계층 다이어그램

Iterable
  │
  ▼
Collection ──────────────────┐
  │                          │
  ├── List                   │
  │   ├── ArrayList          │
  │   ├── LinkedList         │
  │   ├── Vector (legacy)    │
  │   └── CopyOnWriteArrayList
  │                          │
  ├── Set                    │
  │   ├── HashSet            │
  │   ├── LinkedHashSet      │
  │   └── TreeSet            │
  │                          │
  └── Queue / Deque          │
      ├── LinkedList         │
      ├── ArrayDeque         │
      └── PriorityQueue      │
                             │
Map (Collection 밖!)         │
  ├── HashMap                │
  ├── LinkedHashMap          │
  ├── TreeMap                │
  ├── ConcurrentHashMap      │
  └── Hashtable (legacy)     │

1.4 핵심 관찰

1. Iterable이 최상위
   → "순회 가능한 모든 것"
   → for-each 가능
   
2. Collection이 List/Set/Queue의 부모
   → "데이터 모음"의 공통 동작
   
3. Map은 Collection 밖
   → "데이터 모음"이 아니라 "매핑"
   → 다른 추상화

이 그림이 자료구조 선택의 출발점.


2️⃣ List — "순서 있는 컬렉션"

2.1 본질

List의 정의:
  - 순서를 가진 요소들의 컬렉션
  - 중복 허용
  - 인덱스로 접근 가능
  - "위치" 개념이 의미 있음

2.2 "순서"의 정확한 의미

List<String> shipments = new ArrayList<>();
shipments.add("BL-001");
shipments.add("BL-002");
shipments.add("BL-003");

shipments.get(0);   // "BL-001"
shipments.get(1);   // "BL-002"

여기서 "순서" = 삽입 순서.

List의 순서:
  ✓ 삽입한 순서가 보존됨
  ✓ 위치(인덱스)가 의미 있음
  ✗ 정렬된 순서가 아님 (그건 별도 sort 필요)

2.3 자기 점검 — "순서"의 두 가지 의미

"순서가 있다"는 정확히 무엇을 의미하는가?

답:
  1. 삽입 순서 (Insertion Order):
     - 넣은 그대로 유지
     - List, LinkedHashSet, LinkedHashMap의 특성
  
  2. 정렬 순서 (Sorted Order):
     - 자동으로 정렬됨
     - TreeSet, TreeMap의 특성

List는 삽입 순서.
박승제씨가 알아야 할 가장 첫 구분.

2.4 List의 주요 동작

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

// 추가
list.add(s);                  // 끝에 추가
list.add(0, s);              // 특정 위치에 삽입

// 조회
list.get(0);                  // 인덱스로 조회
list.indexOf(s);              // 객체 위치 찾기
list.contains(s);             // 포함 여부

// 수정
list.set(0, newS);            // 특정 위치 변경

// 삭제
list.remove(0);               // 인덱스로 삭제
list.remove(s);               // 객체로 삭제

// 순회
for (Shipment s : list) { ... }
list.forEach(this::process);
list.stream()...

2.5 중복 허용

List<String> list = new ArrayList<>();
list.add("A");
list.add("A");
list.add("A");

list.size();   // 3   ← 모두 보관

→ 같은 값을 N번 넣으면 N번 보관.

2.6 ILIC에서의 사용

// Repository 결과
List<Shipment> shipments = repository.findAll();

// DTO 변환
List<ShipmentResponse> responses = shipments.stream()
    .map(ShipmentResponse::from)
    .toList();

// 다중 화물 정보
public class Shipment {
    private List<Cargo> cargoes;   // 한 운송에 여러 화물
}

가장 흔하게 쓰는 컬렉션.


3️⃣ Set — "중복 없는 컬렉션"

3.1 본질

Set의 정의:
  - 중복 없는 요소들의 컬렉션
  - 순서 보장 없음 (HashSet 기준)
  - 인덱스 없음
  - "포함 여부"가 의미 있음

3.2 중복 제거 메커니즘

Set<String> set = new HashSet<>();
set.add("A");
set.add("A");
set.add("A");

set.size();   // 1   ← 1개만 보관

HashSet이 어떻게 중복을 막나?

1. add("A") 호출:
   - "A".hashCode() 계산
   - 해시 테이블의 해당 버킷 검색
   - 같은 hashCode + equals true인 객체 있나?
     - 있으면 → 추가 안 함
     - 없으면 → 추가

hashCode + equals 가 핵심.

3.3 자기 점검 답변

HashSet은 어떻게 중복을 막는가?

:
1. 내부적으로 HashMap 사용
2. 추가하려는 객체의 hashCode() 계산
3. 해당 버킷에서 equals() 로 동일성 검사
4. 이미 있으면 추가 거부, 없으면 추가

→ Set의 동작은 결국 HashMap의 키 관리.

3.4 hashCode + equals 계약

public class Shipment {
    private Long id;
    private String blNo;
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Shipment)) return false;
        Shipment s = (Shipment) o;
        return Objects.equals(id, s.id);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

규칙:

  • equals true → hashCode 같아야 함
  • hashCode 같음 → equals true 보장 X (해시 충돌 가능)
  • 둘 중 하나만 오버라이드하면 깨짐 → 항상 둘 다

3.5 Set의 종류

HashSet:
  - 순서 없음
  - O(1) add/contains/remove
  - 가장 빠름

LinkedHashSet:
  - 삽입 순서 유지
  - HashSet보다 약간 느림

TreeSet:
  - 정렬 순서 (Comparable / Comparator)
  - O(log n) add/contains/remove
  - 정렬 필요 시

3.6 ILIC에서의 사용

// 중복 제거가 필요한 곳
Set<String> uniqueRoutes = shipments.stream()
    .map(Shipment::getRoute)
    .collect(Collectors.toSet());

// 권한 체크
Set<Permission> userPermissions = ...;
if (userPermissions.contains(Permission.ADMIN)) { ... }

// 처리된 ID 추적
Set<Long> processedIds = new HashSet<>();
for (Shipment s : all) {
    if (processedIds.contains(s.getId())) continue;
    process(s);
    processedIds.add(s.getId());
}

"있나 없나?"가 중요할 때 사용.


4️⃣ Map — "키-값 매핑"

4.1 본질

Map의 정의:
  - 키와 값의 쌍을 저장
  - 키는 중복 불가, 값은 중복 가능
  - 키로 값을 조회
  - "조회"가 핵심 동작

4.2 기본 동작

Map<Long, Shipment> map = new HashMap<>();

// 추가/갱신
map.put(1L, shipment1);
map.put(1L, shipment2);   // 1L이 이미 있으면 값 교체

// 조회
Shipment s = map.get(1L);

// 포함 여부
map.containsKey(1L);
map.containsValue(shipment1);

// 삭제
map.remove(1L);

// 순회
for (Map.Entry<Long, Shipment> entry : map.entrySet()) {
    Long key = entry.getKey();
    Shipment value = entry.getValue();
}

map.forEach((id, s) -> { ... });

4.3 Map의 종류

HashMap:
  - 순서 없음
  - O(1) put/get/remove
  - 가장 빠름
  - 일반적 선택

LinkedHashMap:
  - 삽입 순서 또는 접근 순서 유지
  - HashMap보다 약간 느림
  - LRU 캐시 구현 가능

TreeMap:
  - 키 정렬 순서
  - O(log n)
  - 범위 검색 가능 (subMap, headMap, tailMap)

ConcurrentHashMap:
  - 스레드 안전
  - 멀티스레드 환경
  - 일반 HashMap보다 약간 느림

4.4 Map.Entry — 키-값 한 쌍

Map.Entry<Long, Shipment> entry = ...;
entry.getKey();    // 키
entry.getValue();  // 값

// Java 9+
Map.entry(1L, shipment);   // 불변 Entry 생성

4.5 ILIC에서의 사용

// 캐시
private final Map<Long, Shipment> cache = new HashMap<>();

// 빠른 조회
Map<String, Cargo> cargoesByCode = cargoes.stream()
    .collect(Collectors.toMap(Cargo::getCode, c -> c));

// 그룹핑
Map<String, List<Shipment>> byRoute = shipments.stream()
    .collect(Collectors.groupingBy(Shipment::getRoute));

// 카운팅
Map<String, Long> countByStatus = shipments.stream()
    .collect(Collectors.groupingBy(
        Shipment::getStatus,
        Collectors.counting()));

"키로 값 찾기"가 필요할 때.


5️⃣ 시간 복잡도 비교

5.1 빅 O 표기법 복습

O(1)      : 상수 시간 (입력 크기 무관)
O(log n)  : 로그 시간 (입력 크기 두 배 → 1 단계 더)
O(n)      : 선형 시간 (입력 크기 비례)
O(n²)     : 이차 시간 (입력 크기 제곱)

5.2 List 시간 복잡도

작업ArrayListLinkedList
get(i)O(1)O(n)
add(e) (끝)O(1) amortizedO(1)
add(0, e) (앞)O(n)O(1)
add(i, e) (중간)O(n)O(n)
remove(0)O(n)O(1)
remove(end)O(1)O(1)
contains(e)O(n)O(n)
indexOf(e)O(n)O(n)

관찰:

  • ArrayList: 랜덤 접근(get)이 매우 빠름
  • LinkedList: 앞/뒤 추가/삭제가 빠름
  • 둘 다 contains는 O(n)

→ Unit 5.2, 5.3에서 정밀.

5.3 Set 시간 복잡도

작업HashSetTreeSet
add(e)O(1)O(log n)
contains(e)O(1)O(log n)
remove(e)O(1)O(log n)
정렬 순회O(n log n)O(n)

→ HashSet이 일반적으로 빠름.
→ TreeSet은 정렬 필요 시.

5.4 Map 시간 복잡도

작업HashMapTreeMap
put(k, v)O(1)O(log n)
get(k)O(1)O(log n)
remove(k)O(1)O(log n)
containsKey(k)O(1)O(log n)
키 정렬 순회O(n log n)O(n)
범위 검색O(n)O(log n)

→ Phase 5.4에서 HashMap 내부 정밀.

5.5 자료구조 선택 의사결정

순서가 중요? + 인덱스 접근?
  → ArrayList
  
앞/뒤 자주 추가/삭제?
  → LinkedList 또는 ArrayDeque

중복 제거?
  → HashSet
  
중복 제거 + 정렬?
  → TreeSet
  
키로 빠른 조회?
  → HashMap
  
키 정렬 + 범위 검색?
  → TreeMap
  
삽입 순서 + 빠른 조회?
  → LinkedHashMap (LRU 캐시 패턴)
  
멀티스레드 + Map?
  → ConcurrentHashMap

6️⃣ Map이 Collection의 자식이 아닌 이유

6.1 왜 분리됐나

// Collection 인터페이스
public interface Collection<E> extends Iterable<E> {
    boolean add(E e);
    boolean remove(Object o);
    int size();
    // ...
}

// Map 인터페이스 (Collection이 아님!)
public interface Map<K, V> {
    V put(K key, V value);
    V get(Object key);
    int size();
    // ...
}

이유:

  • Collection은 단일 요소 다룸
  • Map은 키-값 쌍 다룸
  • 동작 시그니처가 근본적으로 다름

6.2 Map의 "Collection 같은 View"

Map은 직접 순회 안 되지만, 세 가지 view 제공:

Map<Long, Shipment> map = ...;

// 1. 키만
Set<Long> keys = map.keySet();

// 2. 값만
Collection<Shipment> values = map.values();

// 3. 키-값 쌍
Set<Map.Entry<Long, Shipment>> entries = map.entrySet();

각 view는 Map과 연결:

  • view 변경 → 원본 Map 변경
  • 원본 Map 변경 → view 반영
  • view = "다른 시각으로 본 같은 데이터"

6.3 그래서 Iterable로?

// ❌ Map은 직접 for-each 안 됨
for (??? entry : map) { ... }

// ✓ entrySet으로 우회
for (Map.Entry<Long, Shipment> entry : map.entrySet()) {
    Long k = entry.getKey();
    Shipment v = entry.getValue();
}

// ✓ forEach 람다
map.forEach((k, v) -> { ... });

→ Java 8+ 의 forEach(BiConsumer) 가 가장 편함.

6.4 Map의 본질 — 함수

수학적으로 Map은 함수:

함수 f: K → V

f("hello") = 42
f("world") = 17

→ 키마다 값이 결정
→ 같은 키로 두 번 호출하면 같은 값 (단, mutable Map)

Collection은 "set/list of elements"지만, Map은 "K에서 V로의 사상".
→ 본질이 다름. 그래서 인터페이스도 분리.


7️⃣ ILIC 실무 — 자료구조 선택 가이드

7.1 가장 흔한 패턴

// 1. DB 결과 보관 → List
List<Shipment> shipments = repository.findAll();

// 2. 중복 제거 → Set
Set<String> uniqueOrigins = shipments.stream()
    .map(Shipment::getOrigin)
    .collect(Collectors.toSet());

// 3. ID로 빠른 조회 → Map
Map<Long, Shipment> shipmentsById = shipments.stream()
    .collect(Collectors.toMap(Shipment::getId, s -> s));

// 4. 그룹핑 → Map<K, List<V>>
Map<String, List<Shipment>> byRoute = shipments.stream()
    .collect(Collectors.groupingBy(Shipment::getRoute));

7.2 잘못된 선택의 예

// ❌ List에서 contains 빈번 호출
List<Long> processedIds = new ArrayList<>();
for (Shipment s : allShipments) {  // 10만 건
    if (processedIds.contains(s.getId())) continue;
    // O(n) × 10만 = 10^10 비교!
    process(s);
    processedIds.add(s.getId());
}

// ✓ Set 사용
Set<Long> processedIds = new HashSet<>();
for (Shipment s : allShipments) {
    if (processedIds.contains(s.getId())) continue;
    // O(1) × 10만 = 10만 비교
    process(s);
    processedIds.add(s.getId());
}

성능 차이:

  • List: ~10초
  • Set: ~10ms
  • 1000배 차이.

7.3 메모리 vs 성능 트레이드오프

ArrayList의 Object[] 배열:
  10000 항목 = 80KB (참조)
  
HashSet의 내부 HashMap:
  10000 항목 = 약 320KB (배열 + Node)
  
TreeMap:
  10000 항목 = 약 400KB (트리 노드)

→ 메모리 약 5배 차이.
→ 메모리 부족 환경에선 고려.

7.4 ILIC의 표준 패턴

도메인 객체 보관:
  List<Shipment>

조회 키로 사용:
  Map<Long, Shipment>

권한/태그/상태 집합:
  Set<Permission>, Set<Tag>

캐싱:
  Caffeine + Map (라이브러리)

설정 상수:
  Set.of(...)        // Java 9+
  Map.of(k1, v1, ...)
  List.of(...)

7.5 불변 컬렉션

// Java 9+
List<String> immutableList = List.of("A", "B", "C");
Set<String> immutableSet = Set.of("A", "B", "C");
Map<String, Integer> immutableMap = Map.of("A", 1, "B", 2);

장점:

  • 안전 (변경 불가)
  • 가벼움 (memory 효율)
  • 멀티스레드 안전

ILIC 상수 정의 시 적극 활용.

7.6 동시성 컬렉션

// 멀티스레드 환경
ConcurrentHashMap<Long, Shipment> sharedMap = new ConcurrentHashMap<>();

// vs
Map<Long, Shipment> map = Collections.synchronizedMap(new HashMap<>());

// vs (Java 8+)
ConcurrentMap<Long, Shipment> concurrentMap = ...;

ConcurrentHashMap:

  • 부분 잠금 (segment 단위)
  • 일반 HashMap만큼 빠름
  • compute, merge 같은 atomic 메서드

→ 멀티스레드 공유 Map은 항상 ConcurrentHashMap.


8️⃣ 흔한 실수 + 잘못된 선택의 사고

실수 1 — List의 contains 남발

List<Long> ids = ...;   // 큰 리스트
for (Item i : items) {
    if (ids.contains(i.getId())) {   // O(n) × m = O(n×m)
        process(i);
    }
}

해결:

Set<Long> idSet = new HashSet<>(ids);
for (Item i : items) {
    if (idSet.contains(i.getId())) {   // O(1) × m = O(m)
        process(i);
    }
}

실수 2 — hashCode/equals 오버라이드 누락

public class Shipment {
    private Long id;
    private String blNo;
    
    // equals/hashCode 없음!
}

Set<Shipment> set = new HashSet<>();
set.add(new Shipment(1L, "BL"));
set.add(new Shipment(1L, "BL"));

set.size();   // 2   ← 의도와 다름!

→ 모든 Entity, VO는 equals + hashCode 반드시 오버라이드.
→ Unit 5.4에서 더 깊이.

실수 3 — Map 키로 mutable 객체

public class Cargo {
    private String code;
    // equals/hashCode가 code 기반
}

Map<Cargo, Integer> map = new HashMap<>();
Cargo c = new Cargo("A");
map.put(c, 1);

c.setCode("B");   // ❌ 키의 hashCode 변경!
map.get(c);       // null (찾지 못함)

→ Map 키는 불변 객체 권장.

실수 4 — TreeMap에 null 키

TreeMap<String, Integer> map = new TreeMap<>();
map.put(null, 1);   // ❌ NullPointerException

이유:

  • TreeMap은 정렬해야 함
  • null과 비교 불가

→ HashMap은 null 키 허용, TreeMap은 불가.

실수 5 — HashMap을 ConcurrentHashMap 대신

// ❌ 멀티스레드에서 HashMap
private static final Map<Long, Shipment> cache = new HashMap<>();

void process(Shipment s) {
    cache.put(s.getId(), s);   // 동시 호출 시 데이터 깨짐
}

해결:

private static final ConcurrentMap<Long, Shipment> cache = new ConcurrentHashMap<>();

실수 6 — Collection.toList() vs Stream.toList()

// Java 16+
List<Shipment> list = stream.toList();   // 불변 List 반환

// Java 8+
List<Shipment> list = stream.collect(Collectors.toList());   // 가변 List

// 차이를 모르면 add() 시도 시 UnsupportedOperationException

실수 7 — Set 순회 순서 가정

Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("C");

for (String s : set) {
    System.out.println(s);   // 어떤 순서? 보장 없음!
}

해결:

  • 삽입 순서 필요 → LinkedHashSet
  • 정렬 순서 필요 → TreeSet

실수 8 — 초기 크기 미지정

// ❌ 100만 건이 들어올 거라 알면서
List<Shipment> list = new ArrayList<>();   // 기본 크기 10
for (int i = 0; i < 1_000_000; i++) {
    list.add(...);   // 매번 확장 → 비효율
}

// ✓ 초기 크기 지정
List<Shipment> list = new ArrayList<>(1_000_000);

→ Unit 5.2 ArrayList 확장 정책에서 자세히.


9️⃣ 면접 질문 + 자기 점검

9.1 면접 단골 질문 매핑

Q핵심 답변
List/Set/Map 차이?순서/중복/키-값
"순서가 있다" 의미?삽입 순서 (정렬 순서 아님)
HashSet이 중복 막는 방법?내부 HashMap의 키 관리 (hashCode + equals)
Map이 Collection 자식 아닌 이유?단일 요소 vs 키-값 쌍. 본질 다름
List에서 contains는?O(n). 빈번하면 Set으로
HashMap의 평균 get/put 시간?O(1)
TreeMap의 시간 복잡도?O(log n). 정렬 필요 시
ArrayList vs LinkedList?랜덤 접근 vs 앞/뒤 추가
hashCode/equals 계약?equals true → hashCode 같음
멀티스레드 Map?ConcurrentHashMap

9.2 자기 점검 체크리스트

기본 이해

  • 컬렉션 인터페이스 계층을 안다
  • List/Set/Map의 본질적 차이를 설명할 수 있다
  • 시간 복잡도 표를 외운다
  • Map이 Collection 자식이 아닌 이유를 안다
  • hashCode/equals 계약을 안다

실전 적용

  • 상황에 맞는 자료구조 선택 가능
  • List.contains 남용 회피
  • 멀티스레드 Map은 ConcurrentHashMap
  • 초기 크기 지정으로 성능 최적화
  • 불변 컬렉션 활용

면접 대비 — 5분 답변

  • 컬렉션 프레임워크 큰 그림
  • 각 자료구조의 시간 복잡도
  • 자료구조 선택 의사결정
  • 잘못된 선택의 실제 사고 예시
  • ConcurrentHashMap의 특성

🎯 핵심 요약 — 3줄 정리

1. 3가지 추상화의 본질

  • List: 순서 + 중복 허용 + 인덱스
  • Set: 중복 제거 (hashCode + equals)
  • Map: 키-값 매핑 (Collection 밖)

2. 시간 복잡도가 선택 좌우

  • ArrayList.get: O(1), LinkedList.add(0): O(1)
  • HashSet/HashMap: O(1), TreeSet/TreeMap: O(log n)
  • List.contains: O(n) → 빈번하면 Set으로

3. ILIC 표준 패턴

  • DB 결과: List
  • 중복 제거: Set
  • 키 조회: Map
  • 멀티스레드: ConcurrentHashMap
  • 상수: List.of, Set.of, Map.of (Java 9+)

📚 다음으로...

Unit 5.2 — ArrayList 내부 (배열 확장 정책)

이번 Unit에서 자료구조의 큰 그림을 봤다면, 다음은 ArrayList의 내부를 직접 들여다보기.

  • ArrayList 기본 크기 10
  • 1.5배 확장 정책
  • elementData 배열의 정체
  • 중간 삽입/삭제 비용
  • 초기 크기 지정의 의미

Phase 5 진행 상황

🚀 Phase 5 — 컬렉션 내부 구조
  ✅ Unit 5.1 List/Set/Map의 본질적 차이 ← 여기
  ⏭ Unit 5.2 ArrayList 내부
  ⏭ Unit 5.3 LinkedList 내부
  ⏭ Unit 5.4 삽입/삭제 효율의 진짜 이유

2주차 진행 상황

✅ Phase 1 — 자바 변수 ↔ 메모리 매핑 (1.1 ~ 1.6 완주)
✅ Phase 2 — JVM 메서드 실행 메커니즘 (2.1 ~ 2.4 완주)
✅ Phase 3 — 바이트코드와 상수 풀 (3.1 ~ 3.4 완주, 정점)
✅ Phase 4 — G1 GC 심화 (4.1 ~ 4.5 완주, 운영 마스터)
🚀 Phase 5 — 컬렉션 내부 구조 (1/4 진행)
⏭ Phase 6 — Reflection & Iterator
⏭ Phase 7 — Buffer
profile
Software Developer

0개의 댓글