1. 와일드카드 (Wildcard)
(1)정의
와일드카드는 "?" 기호를 사용하여 불특정 타입을 다룰 수 있게 해준다. 특히 이미 생성된 제네릭 객체를 파라미터로 받을 때 유용하다.
✅ 핵심: 와일드카드는 제네릭을 정의할 때가 아니라, 사용할 때 사용
1) 기본 예시
class Box<T> {
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; }
}
Box<?> wildcardBox = new Box<String>(); // 모든 타입 수용 가능
2) 비제한 와일드카드 (?)
void print(Box<?> box) {
System.out.println(box.get()); // 읽기 가능
// box.set(...) → 불가!
}
- 읽기만 가능, 쓰기는 불가능 (타입 불확정)
- ? == <? extends Object>와 동일한 의미
3) 상한 와일드카드 (? extends T)
void print(Box<? extends Animal> box) {
Animal a = box.get(); // OK
// box.set(...) → 불가!
}
- T 또는 T의 하위 타입만 받겠다
- get()은 안전 (반환 타입이 상위 타입), set()은 불가
4) 하한 와일드카드 (? super T)
package com.example.generic.ex5;
import com.example.generic.animal.Animal;
import com.example.generic.animal.Cat;
import com.example.generic.animal.Dog;
public class WildcardMain2 {
public static void main(String[] args) {
Box<Object> objectBox = new Box<>();
Box<Animal> animalBox = new Box<>();
Box<Dog> dogBox = new Box<>();
Box<Cat> catBox = new Box<>();
// Animal 포함 상위 타입 전달 가능
writeBox(objectBox);
writeBox(animalBox);
// Animal타입 이거나 상위타입만 가능
// writeBox(dogBox); // 하한이 Animal
Animal animal = animalBox.get();
System.out.println("animal = " + animal.getName());
}
static void writeBox(Box<? super Animal> box) {
box.set(new Dog("멍멍이", 100));
}
}
- T 또는 T의 상위 타입만 받겠다
- set()은 가능, get()은 Object로 반환됨
5) PECS 원칙
- Producer Extends → 데이터를 꺼낼 때는 extends
- Consumer Super → 데이터를 넣을 때는 super
2. 제네릭 메서드
(1) 정의
public static <T> T genericMethod(T t) {
return t;
}
- 메서드 선언부에 <T>가 붙는 것이 핵심
- 메서드 호출 시 타입이 결정됨
(2) 타입 제한
public static <T extends Number> T numberMethod(T t) {
return t;
}
- Number와 그 하위 타입만 허용 (Integer, Double 등)
(3) 타입 추론
Integer result = genericMethod(10); // 컴파일러가 Integer 추론
- 명시적으로 <Integer>를 쓰지 않아도 컴파일러가 자동 추론
(4) 제네릭 메서드 vs 와일드카드
| 구분 | 제네릭 메서드 | 와일드카드 |
| 목적 | 타입을 변경해야 할 때 | 타입을 고정된 범위로 제한할 때 |
| 사용 시점 | 메서드 호출 시 타입 결정 | 이미 생성된 객체를 받을 때 사용 |
| 예시 | <T> T copy(T t) | void print(Box<? extends T>) |
3. 타입 이레이저 (Type Erasure)
(1) 정의
- 자바의 제네릭은 컴파일 타임 전용 기능
- 컴파일 후 .class 파일에서는 모든 타입 정보가 제거됨
(2) 예시
GenericBox<Integer> box = new GenericBox<>();
box.set(10);
Integer result = box.get();
→ 컴파일 후:
GenericBox box = new GenericBox();
box.set(10);
Integer result = (Integer) box.get(); // 컴파일러가 캐스팅 코드 추가
예시 2)
컴파일전
public class AnimalHospitalV3<T extends Animal> {
private T animal;
public void set(T animal) {
this.animal = animal;
}
public void checkup() {
System.out.println("동물 이름: " + animal.getName());
System.out.println("동물 크기: " + animal.getSize());
animal.sound();
}
public T getBigger(T target) {
return animal.getSize() > target.getSize() ? animal : target;
}
}
컴파일 후
public class AnimalHospitalV3 {
private Animal animal;
public void set(Animal animal) {
this.animal = animal;
}
public void checkup() {
System.out.println("동물 이름: " + animal.getName());
System.out.println("동물 크기: " + animal.getSize());
animal.sound();
}
public Animal getBigger(Animal target) {
return animal.getSize() > target.getSize() ? animal : target;
}
}
- T는 지워지고, 상한 타입인 Animal로 대체됨
- 컴파일러가 T에 대해 Animal 타입처럼 사용해도 된다고 판단
- 반환 시에는 호출부에서 타입 캐스팅을 자동 삽입
(3) 타입 매개변수 제한의 경우 – 제한 사항 (한계)
1. instanceof T 사용 불가
public class EraserBox<T> {
public boolean isInstance(Object obj) {
return obj instanceof T; // ❌ 컴파일 오류!
}
}
- 이유: 런타임에 T의 타입 정보가 사라짐 ⇒ T가 무엇인지 JVM은 모름
- 대안: 클래스 타입을 매개변수로 전달받아 사용
2. new T() 생성 불가
public class EraserBox<T> {
public T create() {
return new T(); // ❌ 컴파일 오류!
}
}
- 이유: 자바는 컴파일 시점에만 제네릭 타입을 알고, T의 생성자를 알 수 없음
- 대안: 생성자를 인자로 받거나 리플렉션 사용
3. 제네릭 배열 생성 불가
T[] array = new T[10]; // ❌ 컴파일 오류!
- 이유: 자바는 배열 생성 시 구체적인 타입이 필요하지만, T는 런타임에 존재하지 않음
- 대안: Array.newInstance() 또는 Object 배열을 사용
- 제네릭은 컴파일 시점까지만 존재하고, 런타임에는 모든 타입 정보가 제거됨 (Type Erasure).
그 결과, 타입 매개변수에 대해 다음과 같은 제한이 존재한다.
정리
| 주제 | 요약 |
| 와일드카드 | ?, ? extends, ? super로 표현. 객체를 읽을 때는 extends, 넣을 때는 super. |
| 제네릭 메서드 | 메서드 호출 시 타입을 지정. 반환 타입/입력 타입이 일치할 때 사용. |
| 타입 이레이저 | 컴파일 후 타입 정보가 지워짐. instanceof, new T() 불가능. |
'Java' 카테고리의 다른 글
| 자바 중급 2편 - ArrayList(2) (0) | 2025.07.19 |
|---|---|
| 자바 중급 2편 - ArrayList(1) (0) | 2025.07.07 |
| 자바 중급 2편 - 제네릭(3) (0) | 2025.05.31 |
| 자바 중급 2편 - 제네릭(2) (0) | 2025.05.15 |
| 자바 중급 2편 - 제네릭(1) (0) | 2025.05.11 |