티스토리 뷰

제네릭스(Generics) - 2

와일드카드

  • 매개변수에 과일박스(FruitBox)를 대입하면 주스를 만들어서 반환하는 Jucier 클래스가 있다고 하자. 이 클래스에는 과일을 주스로 만들어 반환하는 makeJuice()라는 static 메서드가 있다.

    class Juicer {
        static Juice makeJuice(FruitBox<Fruit> box) {
            String tmp = "";
            for(Fruit f : box.getList()) {
                tmp += f + " ";
            }
            return new Juice(tmp);
        }
    }
    

    이 메서드의 패러미터 타입을 Fruit타입의 FruitBox 객체로 제한하였기 때문에, Fruit 이외의 타입 은 들어갈 수 없다. (Juicer는 제네릭 클래스도 아니고, 제네릭 클래스라고 하여도 static메서드에서는 T를 사용할 수가 없다) 하지만 Fruit의 자식인 Grape나 Apple 등도 집어넣고 싶다면 어떻게 해야될까?

    FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
    Juicer.makeJuice(fruitBox); // OK
    
    FruitBox<Grape> grapeBox = new FruitBox<Grape>();
    Juicer.makeJuice(grapeBox); // Err! 
    

    이럴 때 사용하기 위해 고안된 것이 바로 와일드카드이다. 와일드카드는 기호 ?로 나타내며 어떠한 타입도 될 수 있다.

    <? extends T> // T와 자손들만 가능
    <? super T> // T와 조상들만 가능
    <?> // 모든 타입 가능. <? extends Object>와 같음 
    
    static Juice makeJuice(FruitBox<? extends Fruit>) {
        ...
    }
    
    FruitBox<Grape> grapeBox = new FruitBox<Grape>();
    Juicer.makeJuice(grapeBox); // OK! 
    

     

  • 와일드카드 예제 코드 (Comparator)

    import java.util.*;
    
    class Fruit {
    	String name;
    	int weight;
    	
    	Fruit(String name, int weight) {
    		this.name = name;
    		this.weight = weight;
    	}
    	
    	public String toString() { return name + "("+  weight +")"; }
    }
    
    class Apple extends Fruit {
    	Apple(String name, int weight) {
    		super(name, weight);
    	}
    }
    
    class Grape extends Fruit {
    	Grape(String name, int weight) {
    		super(name, weight);
    	}
    }
    
    class AppleComp implements Comparator<Apple> {
    	public int compare(Apple t1, Apple t2) {
    		return t2.weight - t1.weight; 
    	}
    }
    
    class GrapeComp implements Comparator<Grape> {
    	public int compare(Grape t1, Grape t2) {
    		return t2.weight - t1.weight; 
    	}
    }
    
    class FruitComp implements Comparator<Fruit> {
    	public int compare(Fruit t1, Fruit t2) {
    		return t2.weight - t1.weight; 
    	}
    }
    
    class FruitBoxEx {
    	public static void main(String[] args) {
    		FruitBox<Apple> appleBox = new FruitBox<Apple>();
    		FruitBox<Grape> grapeBox = new FruitBox<Grape>();
    		
    		appleBox.add(new Apple("GreenApple", 300));
    		appleBox.add(new Apple("GreenApple", 100));
    		appleBox.add(new Apple("GreenApple", 200));
    		
    		grapeBox.add(new Grape("GreenGrape", 400));
    		grapeBox.add(new Grape("GreenGrape", 300));
    		grapeBox.add(new Grape("GreenGrape", 200));
    		
    		Collections.sort(appleBox.getList(), new AppleComp()); 
    		Collections.sort(grapeBox.getList(), new GrapeComp()); 
    		System.out.println(appleBox);
    		System.out.println(grapeBox);
    		System.out.println();
    		Collections.sort(appleBox.getList(), new FruitComp());
    		Collections.sort(grapeBox.getList(), new FruitComp());
    		System.out.println(appleBox);
    		System.out.println(grapeBox);
    	}
    }
    
    class FruitBox<T extends Fruit> extends Box<T> {}
    class Box<T> {
    	ArrayList<T> list = new ArrayList<>();
    	
    	void add(T item) {
    		list.add(item);
    	}
    	
    	T get(int i) {
    		return list.get(i);
    	}
    	
    	ArrayList<T> getList() { return list; }
    	
    	int size() { return list.size(); }
    	
    	public String toString() {
    		return list.toString();
    	}
    }
    

    여기서 Collections.sort()가 사용되었는데 이 메서드의 선언부는 다음과 같다.

    static <T> void sort(List<T> list, Comparator<? super T> c)
    

    <? super T>는 T와 T의 조상들이 매개변수로 올 수 있다는 뜻이다. 매개변수 타입이 Comparator<? super Apple>이라는 의미는 Comparator타입의 매개변수로 Apple과 그 조상인 Fruit, Object가 올 수 있다는 뜻이다. 그래서 FruitComp를 만들면 List<Apple>List<Grape> 모두 정렬할 수 있다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함