와일드 카드 <?>
하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능
다양성 처럼 서로 다른 지네릭타입이 대입된 객체를 다룰 수 있게 된다.
ArrayList<? extends Product> list = new ArrayList<Tv>();
ArrayList<? extends Product> list = new ArrayList<Audio>();
ArrayList<Product> list = new ArrayList<Tv>(); // 에러. 대입된 타입 불일치
- <? extends T> : 와일드 카드의 상한 제한. T와 그 자손들만 가능
- <? super T> : 와일드 카드의 하한 제한. T와 그 조상들만 가능
- <?> : 제한 없음. 모든 타입이 가능. <? extends Object>와 동일
메서드의 매개변수에도 와일드 카드를 사용가능
static Juice makeJuice(FruitBox<? extends Fruit> box) {
String tmp = "";
for(Fruit f: box.getList()) {
tmp += f + " ";
return new Juice(tmp);
}
}
예제
public class Ex2 {
public static void main(String[] args) {
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>(); // 항상 일치해야 함
FruitBox<Apple> appleBox = new FruitBox<Apple>(); // 항상 일치해야 함
//FruitBox<Fruit> appleBox = new FruitBox<Apple>(); // 와일드 카드 적용 전
// Fruit와 그 자손들
FruitBox<? extends Fruit> appleBox2 = new FruitBox<Apple>(); // 와일드 카드 적용 후
appleBox2 = new FruitBox<Fruit>(); // Ok <- 원래 얘만 됨
appleBox2 = new FruitBox<Apple>(); // OK
appleBox2 = new FruitBox<Grape>(); // OK
fruitBox.add(new Apple());
fruitBox.add(new Grape());
appleBox.add(new Apple());
appleBox.add(new Apple());
System.out.println(Juicer.makeJuice(fruitBox));
System.out.println(Juicer.makeJuice(appleBox));
}
}
class Fruit { public String toString() {return "Fruit";}}
class Apple extends Fruit { public String toString() {return "APPLE";}}
class Grape extends Fruit { public String toString() {return "GRAPE";}}
class Juice {
String name;
Juice(String name) {
this.name = name + "주스";
}
public String toString() {
return name;
}
}
class Juicer {
// static Juice makeJuice(FruitBox<Fruit> box) { // appleBox는 들어갈 수 없음
static Juice makeJuice(FruitBox<? extends Fruit> box) { // 둘다 가능
String tmp = "";
for (Fruit f : box.getList()) {
tmp += f + " ";
}
return new Juice(tmp);
}
}
class FruitBox<T extends Fruit> extends Box<T> { }
class Box<T> {
ArrayList<T> list = new ArrayList<T>(); // item을 저장할 박스
void add(T item) { list.add(item);} // 박스에 아이템을 추가
T get(int i) {return list.get(i);} // 박스에서 item을 꺼낼 때
ArrayList<T> getList() {return list;}
int size() { return list.size();} // 박스에 들어간 item 수
public String toString() {return list.toString();}
}
지네릭 메서드
지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)
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) {
...
}
}
메서드를 호출할 때마다 타입을 대입해야 한다.(대부분 생략 가능)
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();
System.out.println(Juicer.makeJuice<Fruit>(fruitBox));
System.out.println(Juicer.makeJuice<Apple>(appleBox));
static <T extends Fruit> Juice makeJuice(FruitBox<T> box) {
String tmp = "";
for (Fruit f : box.getList()) {
tmp += f + " ";
}
return new Juice(tmp);
}
메서드를 호출할 때 타입을 생략하지 않을 때는 클래스 이름 생략 불가
System.out.println(<Fruit>Juicer.makeJuice(fruitBox)); // 클래스 이름 생략불가
System.out.println(this.makeJuice<Fruit>(fruitBox)); // 생략 가능
System.out.println(Juicer.makeJuice<Fruit>(fruitBox)); // 생략 가능
와일드 카드: 하나의 참조변수로 서로 다른 타입이 대입된 여러 지네릭 객체를 다루기 위한 것
지네릭 메서드: 메서드를 호출할 때 마다 다른 지네릭 타입을 대입할 수 있게 한 것
'Java' 카테고리의 다른 글
[Java 복습] 타입 매개변수 제한 (0) | 2024.05.10 |
---|---|
[Java] 지네릭 타입의 형변환 (0) | 2024.05.10 |
[Java] 지네릭 클래스의 제약 (0) | 2024.05.10 |
[Java] Iterator<E>, Map<K, V> (0) | 2024.05.09 |
[Java] 지네릭스란? (0) | 2024.05.09 |