/ JAVAJUNGSUK

Ch12-15~16. 지네릭 타입

자바의 정석 기초편

0. 목차



Chapter12. 지네릭스, 열거형, 애너테이션

Ch12 - 15. 지네릭 타입의 형변환

Ch12 - 16. 지네릭 타입의 제거



Ch12 - 15. 지네릭 타입의 형변환


▶ 지네릭 타입 - 원시 타입 간의 형변환

▷ 가능 하나, 바람직 하지 않음(경고)
Box<object> objBox = null;
Box box = (Box)objBox; // 경고, 지네릭 타입 → 원시 타입
objBox = (Box<object>)box; // 경고, 원시 타입 → 지네릭 타입
▷ 예시1
Box b = new Box<String>();
b. add(new Integer(100)); // 경고
  • 경고 난 이유?
    String에 Integer를 넣었으니까

  • 어쨌든 들어가지는 이유?
      // 보이진 않지만 자동으로 형변환 쳐주고 있는 것
      Box b = (Box)new Box<String>();
    
  • 이렇게 바꾸면?
      Box<String> b = new Box<String>(); // 참조 변수에 <String> 추가
      b. add(new Integer(100)); // 에러
    
▷ 예시2
objBox = (Box<Object>)strBox; // 에러
strBox = (Box<String>)objBox; // 에러
  • 에러 난 이유?
      Box<Object> objBox = null;
      Box<String> strBox = null;
    
      objBox = Box<Object> → Box<String>
      strBox = Box<String> → Box<Object>
    

    이런 형변환은 불가

▶ 와일드 카드가 사용 된 지네릭 타입의 형변환

▷ 가능
Box<Object> objBox = (Box<Object>)new Box<String>(); // 에러, (Box<Object>)이걸로 형변환 불가능

Box<? extends Object> objBox = (Box<? extends Object>)new Box<String>() // OK, 와일드 카드로 형변환 가능
Box<? extends Object> objBox = new Box<String>() // OK, <? extends Object> 생략한 모습, 위 문장과 동일


▶ 실습

▷ 와일드 카드가 사용 된 지네릭 타입의 형변환
  • <Apple> → FruitBox<? extends Fruit>
    FruitBox<? extends Fruit> appleBox = (FruitBox<? extends Fruit>)new FruitBox<Apple>(); // OK
    FruitBox<? extends Fruit> appleBox = new FruitBox<Apple>(); // OK
    
▷ 반대도 가능?
  • FruitBox<? extends Fruit> → <Apple>
    FruitBox<Apple> changeBox = (FruitBox<Apple>)aBox; // 경고
    



Ch12 - 16. 지네릭 타입의 제거


▶ 지네릭 타입과 컴파일러

▷ 지네릭 타입은 컴파일러가 볼 때까지만 생존
▷ 컴파일러가 확인하고 나면 지네릭 타입 제거
▷ 필요한 곳에 형변환을 넣어 줌
  • Object → <T> → 컴파일 → <T> 제거 → Object

▶ 컴파일러가 지네릭 타입 제거하는 과정

▷ 지네릭 타입의 경계(bound)를 제거
class Box<T extends Fruit> {
  void add(T t) {
    ...
  }
}

// ↓↓↓↓컴파일 후↓↓↓↓
class Box {
  void add(Fruit t) { // T 대신 Fruit 넣어줌
    ...
  }
}
▷ 지네릭 타입 제거 후 타입 불일치하면 형변환 추가
T get(int i) {
  return list.get(i); // list의 타입과 반환 타입 T 불일치
}

// ↓↓↓↓컴파일 후↓↓↓↓
Fruit get(int i) {
  return (Fruit)list.get(i); // 제네릭 타입 T가 상속받는 Fruit 타입 가져와서 형변환 추가
}
▷ 와일드 카드가 포함 된 경우 적절한 타입으로 형변환 추가
static Juice makeJuice(FruitBox<? extends Fruit> box) {
  String tmp = " ";

  for(Fruit f : box.getList()) tmp += f + " ";
  
return new Juice(tmp);
}

// ↓↓↓↓컴파일 후↓↓↓↓
static Juice makeJuice(FruitBox box) {
  String tmp = " ";

  for(Fruit f : box.getList().iteroater();) tmp += (Fruit)it.next() + " ";
  
return new Juice(tmp);
}