728x90
반응형
제네릭 와일드카드(Generics Wildcards)
제네릭 와일드카드(Generics Wildcards)는 제네릭 타입을 좀 더 유연하게 사용하기 위해 제공되는 기능이다. 주로 메서드에서 제네릭 타입을 사용할 때 타입의 불확실성을 처리하거나, 특정한 범위의 타입만 허용하도록 할 때 사용한다.
1. 와일드카드의 종류
제네릭 와일드카드는 ?(물음표) 기호를 사용하며, 크게 세 가지 종류가 있다.
와일드카드 | 설명 |
? (Unbounded Wildcard) | 제한이 없는 와일드카드 |
? extends T (Upper Bounded Wildcard) | T 또는 T의 하위 클래스만 허용 |
? super T (Lower Bounded Wildcard) | T 또는 T의 상위 클래스만 허용 |
2. 와일드카드 상세 설명
(1) 제한 없는 와일드카드 (?)
- ?는 어떤 타입이든 올 수 있다는 의미다.
- 특정한 타입을 명시하지 않고, 어떤 타입이라도 허용할 때 사용된다.
예제
import java.util.*;
public class WildcardExample {
public static void printList(List<?> list) { // 어떤 타입이든 허용
for (Object obj : list) {
System.out.println(obj);
}
}
public static void main(String[] args) {
List<String> strList = Arrays.asList("Apple", "Banana", "Orange");
List<Integer> intList = Arrays.asList(1, 2, 3, 4);
printList(strList); // 가능
printList(intList); // 가능
}
}
- List<?> list는 모든 타입의 리스트를 받을 수 있다는 뜻이다.
- 단, list.add()와 같은 요소 추가는 불가능하다. (제네릭 타입 안정성 문제)
(2) 상한 제한 와일드카드 (? extends T)
- ? extends T는 T와 T의 하위 클래스들만 허용한다.
- 주로 읽기 전용으로 사용하며, 리스트에서 값을 가져올 때 유용하다.
예제
import java.util.*;
class Animal {
void sound() {
System.out.println("Some animal sound");
}
}
class Dog extends Animal {
void sound() {
System.out.println("Woof Woof!");
}
}
class Cat extends Animal {
void sound() {
System.out.println("Meow!");
}
}
public class WildcardExample {
// 상한 제한: Animal 또는 Animal의 하위 클래스만 가능
public static void printAnimalSounds(List<? extends Animal> animals) {
for (Animal animal : animals) {
animal.sound(); // 안전하게 호출 가능
}
}
public static void main(String[] args) {
List<Dog> dogs = Arrays.asList(new Dog(), new Dog());
List<Cat> cats = Arrays.asList(new Cat(), new Cat());
printAnimalSounds(dogs); // 가능
printAnimalSounds(cats); // 가능
}
}
- List<? extends Animal>는 Animal과 그 하위 타입(Dog, Cat 등)만 허용
- 그러나 animals.add(new Dog()); 와 같은 요소 추가는 불가능하다.
➡ "읽기(Read)는 가능하지만, 쓰기(Write)는 불가능"
(3) 하한 제한 와일드카드 (? super T)
- ? super T는 T와 T의 상위 클래스만 허용한다.
- 주로 쓰기(Write) 연산이 필요할 때 사용된다.
예제
import java.util.*;
public class WildcardExample {
public static void addNumbers(List<? super Integer> list) {
list.add(10);
list.add(20);
}
public static void main(String[] args) {
List<Number> numbers = new ArrayList<>();
addNumbers(numbers); // 가능
List<Object> objects = new ArrayList<>();
addNumbers(objects); // 가능
// List<Double> doubles = new ArrayList<>();
// addNumbers(doubles); // 오류 발생 (Integer의 상위 클래스가 아님)
}
}
- List<? super Integer>는 Integer와 그 상위 클래스(Number, Object 등)만 허용
- list.add(10); 같은 쓰기(Write)는 가능하지만, list.get(0)을 하면 Object 타입으로 반환됨
➡ "쓰기(Write)는 가능하지만, 읽기(Read)는 제한됨(Object로 반환)"
3. 와일드카드 사용 원칙
와일드카드특징주요 사용 예
? (Unbounded) | 모든 타입 허용 (제한 없음) | 제네릭 타입을 신경 쓰지 않고 리스트를 읽을 때 |
? extends T (상한 제한) | T 및 그 하위 클래스만 허용 (읽기 전용) | 리스트에서 값을 읽을 때 |
? super T (하한 제한) | T 및 그 상위 클래스만 허용 (쓰기 전용) | 리스트에 값을 추가할 때 |
4. 와일드카드와 제네릭 타입의 차이
(1) 제네릭 타입 사용
public static <T> void printListGeneric(List<T> list) {
for (T item : list) {
System.out.println(item);
}
}
➡ printListGeneric(List<T> list)는 고정된 타입을 사용
(2) 와일드카드 사용
public static void printListWildcard(List<?> list) {
for (Object obj : list) {
System.out.println(obj);
}
}
➡ printListWildcard(List<?> list)는 모든 타입을 받을 수 있음
- 제네릭 메서드는 동일한 타입을 유지하면서 사용해야 할 때 유용
- 와일드카드는 여러 타입을 허용하지만, 읽기/쓰기 제한이 있을 수 있음
5. 요약
- ? → 제한 없음 (모든 타입 가능)
- ? extends T → T 및 하위 클래스 (읽기 가능, 쓰기 불가능)
- ? super T → T 및 상위 클래스 (쓰기 가능, 읽기 시 Object로 반환)
728x90
반응형
'프로그래밍 > JAVA' 카테고리의 다른 글
Java ArrayList vs LinkedList 차이점 총정리! 언제, 왜 사용해야 할까? (2) | 2025.03.04 |
---|---|
Java 주요 컬렉션(List, Set, Map)의 특징 및 내부 구조 (1) | 2025.03.04 |
Java 제네릭(Generic) 쉽게 이해하기 – 타입 안정성과 코드 재사용성 극대화 (3) | 2025.03.04 |
Java 리스트(List), Map 의 깊은 복사 완벽 정리 (+ 예제 코드) (0) | 2025.03.03 |
Java 깊은 복사 vs 얕은 복사 완벽 정리 (+ 예제 코드) (0) | 2025.03.03 |
댓글