본문 바로가기
Language/Java

[JAVA] 제네릭 와일드카드의 완벽 이해 : ?, extends, super의 결정적 차이

by Papa Martino V 2026. 1. 18.
728x90

제네릭의 와일드카드(?, ? extends, ? super)
제네릭의 와일드카드(?, ? extends, ? super)

 

자바 제네릭(Generics)을 사용하다 보면 단순히 <T>를 사용하는 것만으로는 해결되지 않는 복잡한 상황에 직면하게 됩니다. 특히 컬렉션 간의 데이터를 복사하거나, 상속 관계에 있는 클래스들을 유연하게 다뤄야 할 때 와일드카드(Wildcard)는 필수적인 도구가 됩니다. 오늘은 많은 개발자가 혼동하는 ?, ? extends T, ? super T의 차이점과 실무 적용 원칙을 깊이 있게 다뤄보겠습니다.


1. 와일드카드(Wildcard)란 무엇인가?

제네릭 와일드카드는 '알 수 없는 타입'을 의미합니다. 기호 ?로 표기하며, 제네릭 타입을 사용할 때 구체적인 타입을 확정 짓지 않고 유연성을 부여하기 위해 도입되었습니다. 와일드카드는 크게 세 가지 형태로 나뉩니다.

  • 비한정 와일드카드 (Unbounded Wildcard): <?> - 모든 타입을 수용합니다.
  • 상한 제한 와일드카드 (Upper Bounded Wildcard): <? extends T> - T와 그 하위 클래스만 수용합니다.
  • 하한 제한 와일드카드 (Lower Bounded Wildcard): <? super T> - T와 그 상위 클래스만 수용합니다.

2. 왜 와일드카드가 필요한가? (공변성과 불공변성)

자바에서 배열은 공변성(Covariant)을 가집니다. 즉, Integer[]Number[]의 하위 타입입니다. 하지만 제네릭은 불공변성(Invariant)을 가집니다. List<Integer>List<Number>의 하위 타입이 아니라는 뜻입니다. 이 제약을 해결하고 다형성을 제네릭에서도 활용하기 위해 와일드카드가 등장했습니다.


3. 와일드카드 유형별 상세 비교

각 와일드카드가 데이터를 읽고 쓰는 방식에 어떤 차이를 주는지 표를 통해 명확히 정리해 보겠습니다.

구분 비한정 와일드카드 (<?>) 상한 제한 (<? extends T>) 하한 제한 (<? super T>)
의미 모든 타입 T와 그 하위 타입 T와 그 상위 타입
데이터 읽기 (Get) Object 타입으로만 읽기 가능 T 타입으로 읽기 가능 Object 타입으로만 읽기 가능
데이터 쓰기 (Add) null만 삽입 가능 null만 삽입 가능 T와 그 하위 타입 삽입 가능
주요 목적 타입에 무관한 기능 수행 생산자 (Producer) 역할 소비자 (Consumer) 역할

4. 핵심 설계 원칙: PECS (Producer-Extends, Consumer-Super)

와일드카드를 언제 사용해야 할지 헷갈린다면 조슈아 블로크가 제안한 PECS 원칙만 기억하면 됩니다.

4.1. Producer-Extends

컬렉션으로부터 데이터를 꺼내와서(Read-only) 무언가를 생산하는 역할이라면 extends를 사용합니다. 예를 들어 List<? extends Number>는 내부 요소를 Number로 안전하게 꺼내어 계산할 수 있음을 보장합니다.

4.2. Consumer-Super

컬렉션에 데이터를 집어넣어(Write-only) 소비하는 역할이라면 super를 사용합니다. List<? super Integer>는 최소한 Integer를 담을 수 있는 공간임을 보장하므로, Integer 및 그 하위 타입을 안전하게 추가할 수 있습니다.


5. 실무에서의 활용 팁

와일드카드는 API 설계 시 사용자에게 극도의 유연성을 제공합니다. 자바 표준 라이브러리의 Collections.copy(List<? super T> dest, List<? extends T> src) 메서드가 대표적인 예입니다. 원본(src)은 데이터를 제공하므로 extends를, 대상(dest)은 데이터를 받으므로 super를 사용하여 타입 안정성을 완벽히 지키면서도 다양한 리스트를 수용합니다.


6. 결론

제네릭 와일드카드는 자바의 타입 시스템을 더욱 견고하고 유연하게 만드는 핵심 장치입니다. extends는 '읽기'에 최적화된 안전망을, super는 '쓰기'에 최적화된 유연함을 제공합니다. PECS 원칙을 코드에 적용하는 순간, 여러분의 라이브러리는 진정으로 재사용 가능한 코드가 될 것입니다.


내용 출처 및 참고 자료

  • Oracle Java Documentation: Wildcards in Generics
  • Effective Java 3rd Edition - Item 31: Use bounded wildcards to increase API flexibility
  • Java Language Specification: Chapter 4.5.1. Type Arguments of Parameterized Types
  • OpenJDK Project Coin: Enhanced Generic Type Inference
728x90