티스토리 뷰

와일드카드 <?>

  • 하나의 참조변수로 대입된 타입이 다른 객체를 참조 가능
  • 메서드의 매개변수에 와일드카드를 사용
더보기

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

ArrayList<? extends Product> list = new ArrayList<Tv>();     // OK
ArrayList<? extends Product> list = new ArrayList<Audio>();  // OK
ArrayList<Product> list = new ArrayList<Tv>();  // 에러. 지네릭 타입 불일치

지네릭 클래스를 생성할 때, 참조변수에 지정된 지네릭 타입과 생성자에 지정된 지네릭 타입은 일치해야 한다.
만일 일치하지 않으면 다음과 같이 컴파일 에러가 발생한다. Product와 Tv가 서로 상속관계라도 마찬가지이다.

<? extends T> 와일드 카드의 상한 제한. T와 그 자손들만 가능

<? super T> 와일드 카드의 하한 제한. T와 그 조상들만 가능

<?> 제한없음. 모든 타입이 가능. <? extends Object>와 동일

<? extends Product>
  • 의미 : Product와 그 자손들
  • 이 예제에서는 Product, Tv, Audio클래스가 이에 해당한다.
<? super Product>
  • 의미 : Product와 그 조상들
  • 이 예제에서는 Product, Object클래스가 이에 해당한다.

메서드의 매개변수에 와일드 카드를 사용

static Juice makeJuice(FruitBox<? extends Fruit> box) {
    String tmp = "";
    for(Fruit f : box.getList()) tmp += f + " ";
    return new Juice(tmp);
}
System.out.println(Juicer.makeJuice(new FruitBox<Fruit>())));  // OK
System.out.println(Juicer.makeJuice(new FruitBox<Apple>())));  // OK

이렇게 메서드 매개변수로 와일드 카드를 사용하면 FruitBox<Fruit>와 FruitBox<Apple> 둘 다 인자로 사용할 수 있다. 와일드 카드를 사용하지 않는다면 FruitBox<Fruit>만 들어올 수 있을 것이다.

static Juice makeJuice(FruitBox<? extends Fruit> box) { // ...
  • 의미 : Fruit와 그 자손들
  • 이 예제에서는 Fruit, Apple클래스가 이에 해당한다.

이처럼 메서드의 매개변수에 와일드 카드를 사용하면, 다형성 효과를 얻을 수 있다. 서로 대입된 지네릭 타입이 다른 객체들을 하나의 매개변수로 받을 수 있게 되는 것이다.

예제12-4

더보기

상속관계도

Ex12_4 클래스들의 상속관계도
일치하지 않으면 컴파일 에러가 발생한다. 상속관계라도 마찬가지이다.

지네릭 클래스를 생성할 때, 참조변수에 지정된 지네릭 타입과 생성자에 지정된 지네릭 타입은 일치해야 한다. 이럴 때 와일드 카드를 쓰면 에러 없이 사용할 수 있다.

public static void main(String[] args) {
    FruitBox2<Fruit2> fruitBox = new FruitBox2<Fruit2>();  // 일치

    // Fruit2와 그 자손들 - Apple2, Grape2
    FruitBox2<? extends Fruit2> appleBox = new FruitBox2<Apple2>();
    appleBox = new FruitBox2<Fruit2>();
    appleBox = new FruitBox2<Apple2>();
    appleBox = new FruitBox2<Grape2>();

지네릭 메서드

  • 지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)
  • 클래스의 타입 매개변수<T>와 메서드의 타입 매개변수 <T>는 별개
  • 메서드를 호출할 때마다 타입을 대입해야(대부분 생략 가능)
  • 메서드를 호출할 때 타입을 생략하지 않을 땐 클래스 이름 생략 불가
더보기

지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)

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

클래스의 타입 매개변수<T>와 메서드의 타입 매개변수 <T>는 별개

메서드를 호출할 때마다 타입을 대입해야(대부분 생략 가능)

메서드를 호출할 때 타입을 생략하지 않을 땐 클래스 이름 생략 불가

드물기 때문에 가볍게 기억만 하자.

지네릭 메서드 와일드 카드 메서드

static Juice makeJuice(FruitBox<? extends Fruit> box) {}      // 와일드 카드 메서드
static <T extends Fruit> Juice makeJuice(FruitBox<T> box) {}  // 지네릭 메서드
  • 와일드 카드는 하나의 참조변수로 서로 다른 타입이 대입된 여러 지네릭 객체를 다루기 위한 것
  • 지네릭 메서드는 메서드를 호출할 때마다 다른 지네릭 타입을 대입할 수 있게 한 것

둘의 용도가 조금 다르다. 와일드 카드를 쓸 수 없을 때 지네릭 메서드를 사용하면 된다.

(이 둘의 차이를 너무 고민하지 말고, 직접 사용해보면서 익혀가자)

'Java의 정석_기초편' 카테고리의 다른 글

열거형  (0) 2022.11.08
지네릭 타입의 형 변환  (0) 2022.11.08
제한된 지네릭 클래스 & 지네릭스의 제약  (0) 2022.11.08
Iterator<E>, HashMap<K,V>  (0) 2022.11.07
지네릭스 용어  (0) 2022.11.07
댓글
공지사항