본문 바로가기
java

Generics 05 와일드 카드, 제네릭 메서드

by 킹차니 2022. 1. 4.

와일드 카드

-하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능하게 한다. (제네릭에 다형성이 가능해진다.)

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