본문 바로가기
language/java

Java Wildcard (<? extends T>, <? super T>) 완벽 이해하기

by 죄니안죄니 2026. 5. 27.
반응형

Java Wildcard (<? extends T>, <? super T>) 완벽 이해하기

Java Generic을 공부하다 보면 거의 반드시 막히는 구간이 바로:

 
<? extends T>
<? super T>
 

입니다.

처음 보면:

도대체 왜 이렇게 복잡하게 쓰지?
 

라는 생각이 들기 쉽습니다.

하지만 실제로 Wildcard는:

  • Collection API
  • Stream API
  • Comparator
  • Spring Framework
  • Java 라이브러리 설계

전체와 매우 깊게 연결됩니다.

그리고 Wildcard를 이해하지 못하면:

  • Generic 에러
  • 타입 제한
  • API 설계
  • Collection 읽기/쓰기

를 제대로 이해하기 어렵습니다.

이번 글에서는:

  • Wildcard란?
  • extends / super 차이
  • 읽기/쓰기 제한
  • PECS 원칙
  • Producer / Consumer
  • 실무 사용 기준

까지 깊게 정리해보겠습니다.


1. Wildcard란?

Wildcard는:

“타입을 정확히 모르지만 범위를 제한하는 Generic 문법”

입니다.

대표 형태:

 
<?>
<? extends T>
<? super T>
 

2. 가장 기본 Wildcard

 
List<?>
 

의미:

“아무 타입 List 가능”
 

입니다.


3. 예시

 
List<String>
List<Integer>
List<User>
 

전부:

 
List<?>
 

로 받을 수 있음.


4. 그런데 왜 필요할까?

예를 들어:

 
void print(List<Object> list)
 

를 만들면:

 
List<String>
 

전달 가능할까?


5. 정답: 불가능

매우 중요.

List<String>
≠
List<Object>
 

입니다.


6. 왜 그럴까?

만약 허용되면:

 
list.add(100);
 

가능해져서:

String List에 Integer 저장 가능
 

문제 발생.


7. 그래서 등장한 것이 Wildcard

 
void print(List<?> list)
 

이렇게 하면:

모든 타입 List 허용
 

가능.


8. 하지만 제약 존재

 
List<?> list
 

에서는:

 
list.add(...)
 

거의 불가능.


9. 왜 add가 안 될까?

현재 JVM 입장에서는:

“무슨 타입인지 모름”
 

입니다.

즉:

안전하게 넣을 수 없음
 

10. 대신 읽기는 가능

 
Object obj = list.get(0);
 

가능.

왜냐하면:

어떤 객체든 Object
 

이기 때문.


11. extends 등장

대표 문법:

 
<? extends Number>
 

12. 의미

Number 또는 그 하위 타입
 

입니다.

즉:

 
Integer
Double
Long
 

등 허용.


13. 사용 예시

 
void print(List<? extends Number> list)
 

14. 가능한 타입

 
List<Integer>
List<Double>
List<Long>
 

전부 가능.


15. 왜 유용할까?

공통 부모 타입 기반 처리 가능.

예:

 
for (Number n : list)
 

가능.


16. extends 핵심 특징

매우 중요.

읽기(Read) 안전
쓰기(Write) 제한
 

입니다.


17. 왜 쓰기 제한될까?

예:

 
List<? extends Number>
 

실제 타입이:

List<Integer>
 

일 수도 있음.

그런데:

 
list.add(Double.valueOf(1.2));
 

허용되면 위험.


18. 그래서 add 불가능

 
list.add(...)
 

거의 금지.

(단 null은 가능)


19. super 등장

대표 문법:

 
<? super Integer>
 

20. 의미

Integer 또는 그 부모 타입
 

입니다.

즉:

 
List<Integer>
List<Number>
List<Object>
 

허용.


21. super 핵심 특징

매우 중요.

쓰기(Write) 안전
읽기(Read) 제한
 

입니다.


22. 왜 쓰기 안전할까?

예:

 
List<? super Integer>
 

이면 최소한:

Integer 저장 가능
 

보장.


23. 읽기는 왜 제한될까?

실제 타입이:

List<Object>
 

일 수도 있기 때문.

즉:

 
Integer i = list.get(0);
 

안전 보장 불가.


24. 그래서 읽을 땐 Object

 
Object obj = list.get(0);
 

만 안전.


25. extends vs super 핵심 비교


문법 의미 읽기 쓰기
<? extends T> T 하위 타입 안전 제한
<? super T> T 부모 타입 제한 안전

26. 이것이 바로 PECS

매우 중요합니다.

Java Generic 핵심 원칙.


27. PECS란?

Producer Extends
Consumer Super
 

28. 의미


역할 사용
데이터를 생산(읽기) extends
데이터를 소비(쓰기) super

29. Producer 예시

 
List<? extends Number>
 

는:

데이터 읽기용
 

에 적합.


30. Consumer 예시

 
List<? super Integer>
 

는:

데이터 저장용
 

에 적합.


31. 실무 예시 1

 
public static <T>
void copy(
    List<? super T> dest,
    List<? extends T> src
)
 

32. 왜 이렇게 설계할까?

src는:

데이터 제공(Producer)
 

 
extends
 

dest는:

데이터 저장(Consumer)
 

 
super
 

33. Stream API에서도 매우 많이 사용

예:

 
Comparator<? super T>
 

34. 왜 super 사용할까?

Comparator는:

비교 대상 소비
 

하기 때문.


35. Collection.addAll()

실제 Java 내부도 비슷.

 
addAll(Collection<? extends E>)
 

36. 이유

추가 대상 Collection은:

데이터 생산자
 

이기 때문.


37. Wildcard 없으면 문제

API 유연성 매우 감소.

즉:

상속 구조 활용 어려움
 

38. Generic과 상속 혼동 주의

매우 중요.

Integer extends Number
 

지만:

List<Integer>
≠
List<Number>
 

입니다.


39. 왜 위험할까?

만약 허용되면:

 
List<Integer> ints = ...

List<Number> nums = ints;

nums.add(Double.valueOf(1.5));
 

가능해짐.

즉:

Integer List 깨짐
 

40. Wildcard 없는 Generic 메서드와 차이

예:

 
<T>
 

는:

구체 타입 추론
 

목적.

Wildcard는:

범위 제한
 

목적.


41. 실무에서 자주 하는 실수

1) extends인데 add 하려 함

컴파일 오류 발생.


2) super인데 읽기 타입 확정하려 함

Object만 안전.


3) PECS 이해 부족

API 설계 어려움.


4) Generic 상속 착각

List<Integer>
≠
List<Number>
 

매우 중요.


42. 핵심 흐름 요약

extends
= 읽기 중심

super
= 쓰기 중심
 

43. 가장 중요한 핵심 한 줄

PECS:
읽기(Producer)는 extends,
쓰기(Consumer)는 super
 

입니다.


44. 정리

Wildcard는 단순 Generic 문법이 아닙니다.

실제로는:

  • Collection API
  • Stream API
  • Comparator
  • Java 라이브러리 설계
  • 타입 안정성

전체와 연결되는 매우 중요한 Generic 핵심 개념입니다.

특히 실무에서는:

  • PECS 원칙
  • extends/super 차이
  • 읽기/쓰기 제한
  • Generic 상속 관계
  • Collection API 설계

를 정확히 이해하는 것이 매우 중요합니다.

다음 글에서는:

Immutable Collection 만들기

를 unmodifiableList, List.of(), defensive copy, 불변 객체 설계까지 포함해서 깊게 정리해보겠습니다.

반응형

댓글