자바의 정석[기초편]으로 공부한 내용을 정리한 글입니다.
하나의 참조 변수로 여러 타입의 제네릭 객체를 참조 가능하게 하기 위한 문법
핵심
ArrayList<? extends Product> list = new ArrayList<Tv>(); // OK
ArrayList<Product> list = new ArrayList<Tv>(); // 에러
- <?>는 와일드 카드라 부르며, "알 수 없는 타입"이라는 의미입니다.
- <? extends Product>는 Product와 그 자손 타입만 허용합니다.
- 예: Product, Tv, Audio 등
- ArrayList<Product> 타입 참조 변수는 ArrayList<Tv>를 받을 수 없습니다.
- 제네릭은 타입까지 일치해야 하므로 불일치 에러 발생.
세 가지 와일드카드 형태
- <? extends T> → T와 그 자손만 허용 (상한 제한)
- <? super T> → T와 그 조상만 허용 (하한 제한)
- <?> → 제한 없음. 모든 타입 허용 (<? extends Object>와 동일)
와일드카드의 메서드 활용
static Juice makeJuice(FruitBox<? extends Fruit> box) { ... }
- FruitBox<Fruit>도 되고 FruitBox<Apple>도 됩니다.
- box.getList()는 Fruit 또는 자손들이므로 Fruit로 처리 가능.
- 호출 예:
makeJuice(new FruitBox<Fruit>());
makeJuice(new FruitBox<Apple>());
즉, Fruit 또는 그 자손 타입의 FruitBox만 허용한다는 의미입니다.
제네릭 메서드
static <T> void sort(List<T> list, Comparator<? super T> c)
- static <T> → 이 메서드 자체가 타입 매개변수 T를 갖는 제네릭 메서드라는 뜻.
- 클래스에서 선언한 <T>와는 별개임.
- 즉, 클래스의 제네릭 타입과는 독립적으로 작동함.
- Comparator<? super T> → T보다 상위 타입도 비교 가능 (예: Integer, Number, Object)
제네릭 메서드와 타입 생략
- 메서드를 호출할 때마다 타입이 바뀌므로 유연함.
- 제네릭 메서드 정의:
static <T extends Fruit> Juice makeJuice(FruitBox<T> box)
- 호출:
makeJuice(fruitBox); // FruitBox<Fruit>
makeJuice(appleBox); // FruitBox<Apple>
- 컴파일러는 fruitBox 또는 appleBox를 보고 타입 T를 유추하므로 <Fruit> 생략 가능.
- 단, 타입 추론이 불가능할 때는 <Fruit> 생략하면 오류 발생.
정리 비교
- FruitBox<T>는 제네릭 클래스
- static <T extends Fruit> Juice makeJuice(FruitBox<T> box)는 제네릭 메서드
- 아래는 와일드카드 사용 예시:
static Juice makeJuice(FruitBox<? extends Fruit> box)
비교 요약:
구분 | 선언 위치 | 의미 |
<T> | 클래스나 메서드에 타입 매개변수 선언 | 직접 타입 지정 필요 |
<?> | 이미 정해진 제네릭 타입의 대입된 타입을 포괄 | 타입 추론만 가능, 메서드 내에서는 읽기 전용 |
<? extends T> | T와 그 자손만 허용 (읽기 전용) | |
<? super T> | T와 그 조상만 허용 (쓰기 전용) |
'Java' 카테고리의 다른 글
애너테이션 (0) | 2025.06.26 |
---|---|
열거형(enum) (0) | 2025.06.26 |
지네릭스 제약네릭스 제약 (0) | 2025.06.25 |
Iterator, HashMap과 지네릭스 (0) | 2025.06.25 |
지네릭 다형성 (0) | 2025.06.25 |