본문 바로가기

Java

[Java] <?> 와일드카드

<?>Java 제네릭에서 와일드카드를 나타내며, 특정 상황에서만 유용하게 사용할 수 있습니다. 모든 상황에서 사용할 수 있지만, 특정 역할과 제약이 있기 때문에 올바른 이해와 사용이 중요합니다.


1. <?>의 역할

<?>아무 타입이나 허용하겠다는 의미로, 불특정 타입을 다룰 때 사용됩니다. 하지만 타입이 명확하지 않기 때문에 제한된 작업만 허용됩니다.

예:

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

위 코드는 어떤 타입의 리스트든 받을 수 있습니다. List<String>, List<Integer> 등 모두 허용됩니다. 하지만 요소 추가와 같은 작업은 제한됩니다.


2. <?>를 사용할 수 있는 상황

다음은 <?>를 사용할 수 있는 주요 상황입니다:

(1) 메서드의 매개변수로 불특정 타입을 받을 때

public void printList(List<?> list) {
    for (Object obj : list) {
        System.out.println(obj);
    }
}

위 메서드는 List<String>, List<Integer>, 또는 List<Map<String, Object>> 등 어떤 리스트든 받을 수 있습니다.


(2) 클래스나 메서드 내부에서 불특정 타입을 다룰 때

List<?> unknownList = new ArrayList<>();
unknownList.add(null); // null만 추가 가능
Object item = unknownList.get(0); // 읽기는 가능

<?>를 사용하면 리스트에서 데이터를 읽을 수 있지만, 타입을 모르기 때문에 타입 안정성이 필요한 작업(예: add)은 제한됩니다.


3. <?>의 제한

<?>는 "아무 타입"이 들어올 수 있다는 의미이므로, 다음과 같은 작업에는 제약이 있습니다:

(1) 요소 추가가 불가능

List<?> list = new ArrayList<>();
list.add("Hello"); // 컴파일 에러!

이유: <?>로 선언된 리스트는 어떤 타입이 들어올지 모르므로, 특정 타입의 값을 추가하는 것이 불가능합니다.

 

예외: null만 추가 가능.

list.add(null); // 가능

(2) 요소 읽기 시 타입 명확성이 없음

List<?> list = List.of(1, 2, 3);
Object value = list.get(0); // Object로만 읽기 가능

<?>는 타입이 불명확하므로, 읽어온 요소의 타입은 항상 Object로 간주됩니다.


4. <?>의 변형: Bounded Wildcards

와일드카드에 제한을 추가할 수도 있습니다:

(1) Upper Bound: <? extends T>

특정 타입 **이하(하위 클래스)**의 타입만 허용합니다.

List<? extends Number> list = new ArrayList<>();
  • List<Integer>, List<Double>Number를 상속하는 타입만 허용.
  • 읽기는 가능하지만 추가는 제한.

(2) Lower Bound: <? super T>

특정 타입 **이상(상위 클래스)**의 타입만 허용합니다.

List<? super Integer> list = new ArrayList<>();
list.add(10); // Integer 추가 가능
  • List<Object>, List<Number>Integer의 상위 클래스만 허용.

5. 언제 사용해야 하는가?

  • 타입에 무관하게 데이터를 읽어야 하는 경우: <?>는 리스트에서 데이터를 읽기만 할 때 적합합니다.
  • 타입 제약을 추가하고 싶을 때: <? extends T> 또는 <? super T>를 사용하여 특정 계층만 허용할 수 있습니다.
  • 타입 안정성이 불필요하거나, 유연성이 필요할 때: 메서드나 클래스에서 다양한 제네릭 타입을 처리하고자 할 때 유용합니다.

6. 실제 사용 예

// 어떤 타입의 리스트든 받아서 출력하는 메서드
public void printList(List<?> list) {
    for (Object obj : list) {
        System.out.println(obj);
    }
}

// 특정 타입 이상의 리스트에 값을 추가
public void addInteger(List<? super Integer> list) {
    list.add(10); // Integer나 그 하위 타입만 추가 가능
}

// 특정 타입 이하의 리스트에서 값 읽기
public void processNumbers(List<? extends Number> numbers) {
    for (Number number : numbers) {
        System.out.println(number.doubleValue());
    }
}

요약

  • <?>는 제네릭 타입을 불특정하게 다룰 때 유용하며, 읽기 작업 위주로 사용됩니다.
  • 요소 추가와 같은 작업에는 제약이 있습니다.
  • 특정 타입 계층을 다루어야 할 경우, <? extends T> 또는 <? super T>를 사용합니다.

'Java' 카테고리의 다른 글

[XML] "문자열".equals(변수) vs 변수.equals("문자열")  (0) 2024.11.26