Ch12-12~14. 와일드 카드
0. 목차
Chapter12. 지네릭스, 열거형, 애너테이션
Ch12 - 12. 와일드 카드
Ch12 - 13. 와일드 카드 예제
Ch11 - 14. 지네릭 메서드
Ch12 - 12. 와일드 카드
▶ 와일드 카드 < ? > 란?
▷ 하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능
- 원래는
참조 변수의 <>와 생성자 <> 무조건 일치!
- 와일드 카드 < ? >를 사용하면
참조 변수의 <?>와 생성자 <> 불일치 가능
Arraylist<? extends Product> list = new ArrayList<Tv>(); // OK Arraylist<? extends Product> list = new ArrayList<Audio>(); // OK Arraylist<Product> list = new ArrayList<Audio>(); // ERROR! 매개 변수화 된 타입은 불일치
▷ 메서드의 매개 변수에 와일드 카드를 사용
class Fruit { }
class Apple extends Fruit { }
static Juice makeJuice(FruitBox<? extends Fruit> box) {
String tmp = "";
for (Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
System.out.println(Juice.makeJuice(new FruitBox<Fruit>())); // 와일드 카드 있든 없든 가능
System.out.println(Juice.makeJuice(new FruitBox<Apple>())); // 와일드 카드 없으면 불가능
- 와일드 카드가 있을 때,
System.out.println(Juice.makeJuice(new FruitBox<Apple>()));
= static Juice makeJuice(FruitBox<? extends Fruit> box)
= static Juice makeJuice(FruitBox<? extends Fruit> box = new FruitBox<Apple>()))
Fruit 포함 Fruit의 자손들 가능
- 와일드 카드가 없을 때,
System.out.println(Juice.makeJuice(new FruitBox<Apple>()));
= static Juice makeJuice(FruitBox<Fruit> box)
= static Juice makeJuice(FruitBox<Fruit> box ≠ new FruitBox<Apple>())) // ERROR!
Fruit만 가능
▶ 와일드 카드 < ? >의 종류
▷ <? extends T>
: 와일드 카드의 상한 제한, T와 그 자손들만 가능
▷ <? super T>
: 와일드 카드의 하한 제한, T와 그 조상들만 가능
▷ <?>
: 제한 없음, 모든 타입 가능, <? extends Object>
와 동일
Ch12 - 13. 와일드 카드 예제
▶ 와일드 카드 사용하여 객체 생성 해 보기
▷ Fruit와 그 자손을 받을 수 있는 와일드 카드 사용
class Fruit implements Eatable { public String toString() {return "Fruit";} }
interface Eatable { }
class Apple extends Fruit { public String toString() {return "Apple";} }
class Grapes extends Fruit { public String toString() {return "Grapes";} }
FruitBox<? extends Fruit> fruitBox = new FruitBox<Fruit>();
▷ fruitBox에 담을 수 있는 건? Fruit, Fruit를 상속받는 Apple과 Grapes
fruitBox = new FruitBox<Fruit>();
fruitBox = new FruitBox<Grapes>();
fruitBox = new FruitBox<Apple>();
▶ Fruit에 든 과일 + 쥬스 출력
▷ Juice 붙여주는 클래스 생성 : — + “Juice”
class Juice {
String name;
Juice(String name) { this.name = name + "Juice"; }
public String toString() { return name; }
}
▷ 와일드 카드로 매개 변수를 받아 list에 담긴 과일 이름 가져오기
class Juicer {
static Juice makeJuice(FruitBox<? extends Fruit> box) {
String tmp = " ";
for(Fruit f : box.getList())
tmp += f + " ";
return new Juice(tmp);
}
}
▷ Box에 list 전체를 출력 해 주는 메서드 추가
class Box<T> {
ArrayList<T> list = new ArrayList<T>();
void add(T item) { list.add(item); }
T get(int i) { return list.get(i); }
int size() { return list.size(); }
ArrayList<T> getList() { return list; }
public String toString() {return list.toString(); }
}
▷ 매개 변수로 과일 박스 넣어주고 돌려보기
public static void main(String[] args) {
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();
FruitBox<Grapes> grapesBox = new FruitBox<Grapes>();
fruitBox.add(new Fruit());
fruitBox.add(new Apple());
fruitBox.add(new Grapes());
appleBox.add(new Apple());
grapesBox.add(new Grapes());
System.out.println(Juicer.makeJuice("fruitBox : " + fruitBox));
System.out.println(Juicer.makeJuice("appleBox : " + appleBox));
System.out.println(Juicer.makeJuice("grapesBox : " + grapesBox));
}
// console
fruitBox : Fruit Apple Grapes Juice
appleBox : Apple Juice
grapesBox : Grapes Juice
static Juice makeJuice(FruitBox<? extends Fruit> box)
: Fruit의 자손들은 다 받음- 그래서
fruitBox
,appleBox
,grapesBox
다 넣기 가능
Ch12 - 14. 지네릭 메서드
▶ 지네릭 메서드란?
▷ 메서드에 타입 변수가 선언 된 것
▷ 타입 변수는 메서드 내에서만 유효
static <T> void sort(List<T> list, Comparator<? super T> c)
▷ 클래스 타입 매개 변수<T>
와 메서드 타입 매개 변수<T>
는 별개
class FruitBox<T> {
...
static <T> void sort(List<T> list, Comparator<? super T> c) {
...
}
}
클래스 타입 매개 변수 문자 T ≠ 메서드 타입 매개 변수 문자 T
- 같아도 다름
- 같아도 다름
클래스 타입 매개 변수 String vs 메서드 타입 매개 변수 Integer = 가능
클래스 타입 매개 변수 String vs 메서드 타입 매개 변수 String = 가능
- 클래스 타입 매개 변수와 메서드 타입 매개 변수는 같아도 되고 달라도 됨
- 클래스 타입 매개 변수와 메서드 타입 매개 변수는 같아도 되고 달라도 됨
- 메서드 내에서 T가 사용 되었으면 메서드 타입 매개 변수 T!
가까운 거 사용
▶ 지네릭 메서드 사용 시
▷ 메서드를 호출할 때마다 타입을 대임해야 함
▷ 대부분 생략 가능
FuitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FuitBox<Apple> appleBox = new FruitBox<Apple>();
...
static <T extends Fruit> Juice makeJuice(FruitBox<T> box) { // Fruit과 그의 자손(Apple) 대입 가능
String tmp = " ";
for(Fruit f : box.getList()) tmp += f + " ";
return new Juice(tmp);
}
...
System.out.println(Juicer.<Fruit>makeJuice(fruitBox)); // 메서드에 타입<Fruit>을 붙여 호출
System.out.println(Juicer.<Apple>makeJuice(appleBox)); // 메서드에 타입<Apple>을 붙여 호출
- 호출 시 타입을 작성하지 않아도 어떤 타입인지 알 수 있음 → 타입 생략 가능
▷ 단, 메서드 호출 시 타입 작성하면 클래스 이름 생략 불가
System.out.println(<Fruit>makeJuice(fruitBox)); // ERROR! 타입 작성 시 클래스 이름 생략 불가!
System.out.println(this.<Fruit>makeJuice(fruitBox)); // OK
System.out.println(Juicer.<Fruit>makeJuice(fruitBox)); // OK
▶ 지네릭 메서드 ≠ 와일드 카드
▷ 지네릭 메서드
- 메서드를 호출할 때마다 다른 지네릭 타입을 대입할 수 있게 한 것
static <T extends Fruit> Juice makeJuice(FruitBox<T> box) { String tmp = " "; for(Fruit f : box.getList()) tmp += f + " "; return new Juice(tmp); }
▷ 와일드 카드
- 하나의 참조 변수로 서로 다른 타입이 대입 된 여러 지네릭 객체를 다루기 위한 것
static Juice makeJuice(FruitBox<? extends Fruit> box) { String tmp = " "; for(Fruit f : box.getList()) tmp += f + " "; return new Juice(tmp); }
와일드 카드를 사용할 수 없으면 지네릭 메서드를 만듦