본문 바로가기

자바 (Java)/요약

Chpt 12. 지네릭스, 열거형, 애너테이션 - 주제 2. 지네릭스의 타입

728x90

1. 지네릭 타입과 다형성

 

앞서 참조 변수의 타입과 인스턴스의 타입은 다형성(조상이 자손 참조)이 가능하지만 지네릭 타입은 서로 일치해야 한다.

 

(1) ArrayList<Tv> list = new ArrayList<Tv>(); // O
(2) ArrayList<Product> list = new ArrayList<Tv>(); // X
(3) List<Tv> list = new ArrayList<Tv>(); // O
(4) List<Product> list = new ArrayList<Tv>(); // X

 

  원시 타입 지네릭 타입
다형성 가능 여부 O X

 

ArrayList<Product> product = new ArrayList<Product>(); 를 사용해 product의 ArrayList에 Product 타입의 자손 객체를 담을 수 있다. 이때 형변환을 해야함을 잊지 말자.

 

2. 지네릭 타입의 제한

 

대입되는 지네릭 타입을 제한해줄 때는 다음과 같이 한다.

 

class FruitBox<T extends Fruit & Eatable> {

    ....

}

 

이때 타입 매개변수 T에는 Fruit과 그 자손 객체만 대입이 가능하다. 인터페이스 구현 시에도 extends를 사용하며 extends 뒤에 두 개 이상의 타입이 올 때는 &로 연결한다.

 

[예 2-1]

 

참고

 

3. 와일드 카드

 

지네릭스의 와일드 카드는 1에서 불가능했던 지네릭 타입 간에 다형성을 가능하게 해준다. 

 

  ?에 올 수 있는 타입
(1) <? extends T> T와 그 자손 객체들 (? <= T)
(2) <? super T> T와 그 조상 객체들 (? >= T)
(3)  <?> (<? extends Object>) 모든 타입

 

 

[예 3-1]

 

static Juice makeJuice(FruitBox<? extends Fruit> box) {

    String tmp = "";

    ....

    return new Juice(tmp);

}

 

Juice.makeJuice(new FruitBox<Fruit>()); // O
Juice.makeJuice(new FruitBox<Apple>()); // O

 

[참고] 와일드 카드와 지네릭 메서드

  와일드 카드 지네릭 메서드
static Juice makeJuice(FruitBox<? extends Fruit> box) {
    String tmp = "";
    ....
    return new Juice(tmp);
}
static <T extends Fruit> makeJuice(FruitBox<T> box) {
    String tmp = "";
    ....
    return new Juice(tmp);
}
용도 하나의 참조 변수로 여러 지네릭 타입을 다루기 위함 메서드를 호출할 때마다 서로 다른 타입을 대입할 수 있게 함

 

둘의 용도를 잘 구별하고 보통 와일드 카드가 안될 때 지네릭 메서드를 쓰고는 한다. 둘의 차이에 대해 너무 신경 쓰지 말고 일단 사용하는데 집중하자.

 

[참고] 타입 (매개)변수 (T) vs. 지네릭 타입 (<T>)

static 멤버에는 T를 못 쓰지 <T>는 사용할 수 있다. 둘을 혼동하지 않도록 하자.

 

4. 지네릭 타입의 형변환

 

1) 지네릭 타입 ↔ 원시 타입

 

Box box = null;

Box<Object> objBox = null;

 

box = (Box) objBox; // 지네릭 타입 → 원시 타입 (O)
objBox = (Box<Object>) box;  // 원시 타입 → 지네릭 타입 (O)

 

하지만 둘 다 경고가 발생한다.

 

2) (서로 다른 지네릭 타입 간) 지네릭 타입 ↔ 지네릭 타입

 

1에서도 알 수 있듯이 불가하다. 

 

3) 지네릭 타입 와일드 카드를 포함한 지네릭 타입

 

Box<? extends Object> wBox = new Box<String>(); 
Box<String> sBox = (Box< String>) wBox; // 와일드 카드를 포함한 지네릭 타입 → 지네릭 타입 (O)

 

[예 3-1]을 참고하면 다음과 같다.

 

FruitBox<? extends Fruit> box = (FruitBox<? extends Fruit>) new FruitBox<Fruit>();
FruitBox<? extends Fruit> box = (FruitBox<? extends Fruit>) new FruitBox<Apple>();

 

모두 해당 형변환이 생략돼 있었던 것이다. 

 

5. 지네릭 타입의 제거

 

컴파일러는 컴파일 전 지네릭 타입을 제거하고 필요하면 형변환을 추가해준다.

반응형