본문 바로가기

Java

[Java] 와일드 카드, 지네릭 메서드

와일드 카드 <?>

하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능

다양성 처럼 서로 다른 지네릭타입이 대입된 객체를 다룰 수 있게 된다.

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