<?>는 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 |
---|