BE/Java

[Java] 제네릭 vs 와일드카드

baek-dev 2025. 9. 4. 18:27

제네릭과 와일드카드의 차이

1. 제네릭 (Generics)

  • 클래스나 메서드가 다룰 데이터 타입을 파라미터화해서, 컴파일 시점에 타입 안전성을 보장하는 문법임.
  • 선언 시점에 타입을 확정지음 → 컴파일러가 타입 체크 가능.

예시

List<String> names = new ArrayList<>(); 
names.add("철수");  // OK
names.add(123);    // 컴파일 에러
  • List<String> 제네릭을 통해 "이 리스트는 문자열만 담는다" 라는 타입 정보를 컴파일러에 알려줌.
  • 잘못된 타입(Integer)을 넣으면 컴파일 단계에서 막힘.

2. 와일드카드 (Wildcard)

  • 제네릭 타입을 다룰 때, 정확한 타입을 지정하지 않고 유연하게 범위를 한정하고 싶을 때 사용함.
  • ? 로 표현됨.
  • 제네릭의 소비/생산(Producer/Consumer) 관점에서 자주 등장.

종류

  1. 비한정 와일드카드 <?>
    • "어떤 타입이든 들어올 수 있음"
    List<?> list = new ArrayList<String>();
    list = new ArrayList<Integer>();
    
    • 단, 안전하지 않으므로 요소 추가는 불가(null만 가능).
    • 요소 조회만 가능.
  2. 상한 제한 와일드카드 <? extends T>
    • "T 또는 T의 하위 타입만 올 수 있음"
    • 읽기(Producer) 용도
    List<? extends Number> list = new ArrayList<Integer>();
    Number n = list.get(0);   // OK
    // list.add(10);          // 컴파일 에러 (추가 불가)
    
  3. 하한 제한 와일드카드 <? super T>
    • "T 또는 T의 상위 타입만 올 수 있음"
    • 쓰기(Consumer) 용도
    List<? super Integer> list = new ArrayList<Number>();
    list.add(10);    // OK (Integer는 허용)
    // Integer i = list.get(0); // 불가능 (Object로만 꺼낼 수 있음)
    

3. 핵심 차이

구분 제네릭 와일드카드
선언 위치 클래스/인터페이스/메서드 정의 시 사용 이미 정의된 제네릭 타입을 사용할 때 유연성을 위해 사용
타입 확정 여부 구체적인 타입을 지정 (List<String>) 타입을 알 수 없거나 범위를 지정 (List<?>, List<? extends Number>)
목적 컴파일 시점 타입 안정성 확보 메서드 파라미터의 유연성 확보
활용 직접 사용하는 코드 API 설계 시 (라이브러리, 범용 메서드)

4. 직관적인 비유

  • 제네릭은 "이 상자에는 사과만 담을 거야" 라고 처음부터 딱 정해버리는 것.
  • 와일드카드는 "어떤 과일이 들어있을지 모르지만 과일 계열만 올 수 있어" 혹은 "과일 이상(슈퍼클래스)만 허용할게" 라고 범위를 열어두는 것.

5. 예시 비교

// 제네릭 방식
public <T> void printList(List<T> list) {
    for (T elem : list) {
        System.out.println(elem);
    }
}

// 와일드카드 방식
public void printList(List<?> list) {
    for (Object elem : list) {
        System.out.println(elem);
    }
}
  • 제네릭은 T를 선언해서 내부적으로 타입을 유지할 수 있음.
  • 와일드카드는 읽기 전용 느낌 → 타입 정보를 유지하지 않음.

6. 정리

  • 제네릭: 타입 안정성 확보 (직접 코드 작성할 때 주로 사용)
  • 와일드카드: 유연성 확보 (API 설계, 범용 라이브러리에서 자주 사용)
  • PECS 원칙 (Producer Extends, Consumer Super)
    • <? extends T> → 데이터를 꺼내(Produce) 읽기 전용
    • <? super T> → 데이터를 집어넣기(Consume) 전용

 

 

 

 

출처 : ChatGPT

'BE > Java' 카테고리의 다른 글

변수 정리  (3) 2025.07.22
중첩, 내부클래스  (2) 2025.07.21
LocalDate.parse(입력문자,포맷);  (1) 2025.05.29
date.format()  (0) 2025.05.28
DateTimeFormatter.ofPattern  (0) 2025.05.27