본문 바로가기
language/java

List.of에 대하여

by 죄니안죄니 2026. 6. 1.
반응형

1. 우리가 보는 것은 이것뿐이다.

 
List<String> list = List.of("A", "B");
 

우리는

 
List
 

를 받는다고만 생각한다.


2. 그런데 List는 인터페이스다.

 
public interface List<E> {
    ...
}
 

인터페이스는 객체를 만들 수 없다.

 
new List<>();   // 컴파일 에러
 

즉,

 
List.of(...)
 

는 내부에서 반드시 어떤 구현체를 생성해서 반환해야 한다.


3. 내부에서는 이런 식으로 동작한다. (개념적으로)

 
public static <E> List<E> of(E... elements) {

    if (elements.length == 0) {
        return new List0<>();
    }

    if (elements.length == 1) {
        return new List1<>(elements[0]);
    }

    if (elements.length == 2) {
        return new List12<>(elements[0], elements[1]);
    }

    return new ListN<>(elements);
}
 

실제 JDK 코드도 거의 이런 구조다.


4. 왜 굳이 여러 클래스를 만들었을까?

예를 들어

원소가 1개인 경우

 
List<String> list = List.of("A");
 

굳이

 
Object[] array = new Object[1];
 

를 만들 필요가 없다.

그냥

 
class List1 {
    Object e0;
}
 

이 메모리를 더 적게 사용한다.


원소가 2개인 경우

 
List.of("A", "B");
 

 
class List12 {
    Object e0;
    Object e1;
}
 

처럼 저장하면 배열을 만들지 않아도 된다.


원소가 많으면

 
List.of("A", "B", "C", "D");
 

이건 개수를 알 수 없으므로

 
class ListN {
    Object[] elements;
}
 

를 사용한다.


5. 실제로 확인해보면

 
List<String> list1 = List.of();
List<String> list2 = List.of("A");
List<String> list3 = List.of("A", "B");
List<String> list4 = List.of("A", "B", "C");

System.out.println(list1.getClass());
System.out.println(list2.getClass());
System.out.println(list3.getClass());
System.out.println(list4.getClass());
 

출력(Java 버전에 따라 조금 다를 수 있음)

class java.util.ImmutableCollections$ListN
class java.util.ImmutableCollections$List12
class java.util.ImmutableCollections$List12
class java.util.ImmutableCollections$ListN
 

6. 그럼 왜 내가 신경 안 써도 되는데?

내 코드는

 
List<String> list = List.of("A", "B");
 

뿐이다.

나는

ArrayList인지?
LinkedList인지?
List12인지?
ListN인지?
 

알 필요가 없다.

왜냐하면

 
list.get(0);
list.size();
list.contains("A");
 

같은 List 인터페이스만 사용하면 되기 때문이다.


7. 만약 생성자를 썼다면?

예를 들어

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

라고 하면

나는 이미

ArrayList
 

라는 구현체에 의존하게 된다.

JDK가

더 좋은 구현체가 있으니 이걸 써라
 

라고 해도 내 코드는 바뀌어야 한다.


8. Static Factory Method가 좋은 이유가 여기서 나온다.

 
List<String> list = List.of(...);
 

만 호출하면

JDK 개발자는 내부에서

Java 9 : List12 사용
Java 17 : List12 개선
Java 21 : 더 빠른 ListX 개발
Java 25 : 완전히 새로운 구현체
 

로 얼마든지 변경할 수 있다.

하지만 사용자 코드는

 
List<String> list = List.of(...);
 

한 줄도 수정할 필요가 없다.


핵심 한 줄

Static Factory Method의 "구현체를 숨긴다"는 의미는 "사용자는 List라는 인터페이스만 알고, 실제 반환되는 객체(List12, ListN, ArrayList, ImmutableList 등)는 라이브러리 작성자가 자유롭게 선택하고 변경할 수 있다"는 뜻이다.

즉,

 
List<String> list = List.of("A", "B");
 

에서 list의 컴파일 타입은 List이고, 런타임 실제 객체 타입은 JDK가 선택한 내부 구현체인 것이다.

반응형

댓글