와일드 카드
-하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능하게 한다. (제네릭에 다형성이 가능해진다.)
ArrayList<? extends Product> list = new ArrayList<TV>(); //OK
ArrayList<? extends Product> list = new ArrayList<Audio>(); //OK
ArrayList<Product> list = new ArrayList<TV>(); //ERROR! 대입된 타입 불일치
와일드 카드를 사용하면 3번째처럼 타입이 일치하지 않아도 참조 가능하다.
/* 와일드 카드의 종류 */
<? extends T> 와일드 카드의 상한 제한. T와 그 자손들만 가능.
<? super T> 와일드 카드의 하한 제한. T와 그 조상들만 가능.
<?> 제한 없음. 모든 타입이 가능 <? extends Object>와 동일
<? extends T>
<? super T>
-메서드의 매개변수에 와일드 카드를 사용
static Juice makeJuice(FruitBox<? extends Fruit> box){
String tmp = "";
for(Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
//아래처럼 Apple과 Cherry타입 가능
makeJuice(new FruitBox<Apple>);
makeJuice(new FruitBox<Cherry>);
//appleBox는 Fruit을 extends한 타입을 사용한 모든 FruitBox의 참조 변수가 될 수 있다.
FruitBox<? extends Fruit> appleBox = new FruitBox<>();
appleBox = new FruitBox<Fruit>();
appleBox = new FruitBox<Apple>();
appleBox = new FruitBox<Cherry>();
EX)
public class Juicer{
public static Juice makeJuice(FruitBox<? extends Fruit> box){
String tmp = "";
for (Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
}
public class EX06 {
public static void main(String[] args) {
FruitBox<Fruit> fruitBox = new FruitBox<>();
FruitBox<Apple> appleBox = new FruitBox<>();
fruitBox.add(new Apple());
fruitBox.add(new Cherry());
appleBox.add(new Apple());
appleBox.add(new Apple());
System.out.println(Juicer.makeJuice(fruitBox));
System.out.println(Juicer.makeJuice(appleBox));
}
}
제네릭 메서드
- 제네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)
- 메서드를 호출할 때마다 다른 제네릭 타입을 대입할 수 있게 해준다.
static <T> void sort(List<T> list, Comparator<? super T> c)
- 클래스 타입의 매개변수<T>와 메서드의 타입 매개변수 <T>는 별개
//클래스의 T와 메서드의 T는 다른 타입변수이다.
class FruitBox<T> {
//아래 메서드에 선언된 T는 sort메서드 안에서만 사용가능하다.
//만약 클래스에 선언된 T와 sort에 선언된 T가 일치한다면 메서드 내에서는 sort의 T가 우선한다.
static <T> void sort(List<T> list, Comparator<> super T> c){
...
}
}
- 메서드를 호출할 때마다 타입을 대입해야한다.(대부분 생략 가능)
// Juicer클래스에 아래와 같은 메서드가 있다.
// static 뒤에 붙은 "<T extends Fruit>"은 makeJuice의 인자인 "FruitBox<T> box"의
// T가 <T extends Fruit>. 즉 Fruit의 자손이어야 한다는 것이다.
static <T extends Fruit> Juice makeJuice(FruitBox<T> box){
String tmp = "";
for(Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();
System.out.println(Juicer.<Fruit>makeJuice(fruitBox));
System.out.println(Juicer.<Apple>makeJuice(appleBox));
- 메서드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름을 생략 불가
System.out.println(<Fruit>makeJuice(fruitBox)); //ERROR. 클래스 이름 생략 불가
System.out.println(this.<Fruit>makeJuice(fruitBox));//OK
System.out.println(Juicer.<Fruit>makeJuice(fruitBox)); //OK
System.out.println(<Fruit>makeJuice(fruitBox)); //ERROR. 클래스 이름 생략 불가
System.out.println(this.<Fruit>makeJuice(fruitBox));//OK
System.out.println(Juicer.<Fruit>makeJuice(fruitBox)); //OK
출처: 남궁성님 유튜브 강의
https://www.youtube.com/user/MasterNKS
'java' 카테고리의 다른 글
Enum 열거형 (0) | 2022.04.15 |
---|---|
Generics 05 제네릭 형 변환 (0) | 2022.01.04 |
Generics 04 제한된 제네릭 클래스(제네릭스의 제약) (0) | 2022.01.03 |
Generics 03 Iterator, HashMap과 제네릭스 (0) | 2022.01.03 |
Generics 02 제네릭스 용어, 제네릭 타입과 다형성 (0) | 2022.01.02 |