Ch12-9~11. 지네릭 클래스
0. 목차
Chapter12. 지네릭스, 열거형, 애너테이션
Ch12 - 9. 제한된 지네릭 클래스
Ch12 - 10. 제한된 지네릭 클래스 예제
Ch11 - 11. 지네릭스의 제약
Ch12 - 9. 제한된 지네릭 클래스
▶ 제한된 지네릭 클래스란?
▷ extends로 대입할 수 있는 타입을 제한
- T가 extends 하는 클래스의 자손만 타입으로 지정가능
class FruitBox<T extends Fruit> { ArrayList<T> list = new ArrayList<T>(); }
<T>
: 모든 타입 가능<T extends Fruit>
: Fruit포함, Fruit의 자손 타입만 가능
FruitBox<Apple> appleBox = new FruitBox<Apple>(); // OK FruitBox<Toy> toyBox = new FruitBox<Toy>(); // ERROR! Toy는 Fruit 자손 아님
▷ 인터페이스도 implements가 아닌 extends 사용
interface Eatable { }
class FruitBox<T extends Eatable> { ... } // interface를 구현하는데도 extends 사용
Ch12 - 10. 제한된 지네릭 클래스 예제
▶ 필요한 클래스 생성 : 자기 클래스 이름 반환
▷ interface Eatable { }
▷ Eatable을 구현하는 Fruit { }
▷ Fruit을 상속 받는 Apple { }
▷ Fruit을 상속 받는 Grapes { }
class Fruit implements Eatable { public String toString() {return "Fruit";} }
interface Eatable { }
class Apple extends Fruit { public String toString() {return "Apple";} }
class Grapes extends Fruit { public String toString() {return "Grapes";} }
class Toy { public String toString() { return "Toy";}}
▶ FruitBox 클래스 생성
▷ FruitBox
는 Fruit
의 자손을 제네릭스로 받으며 Box
를 상속받음
class FruitBox<T extends Fruit & Eatable> extends Box<T> { }
▶ Box 클래스 생성
▷ T
(Object)를 타입 변수로 받는 제네릭 클래스
▷ ArrayList<T>
생성
▷ FruitBox에 add하면 여기의 list.add()를 통해 list에 추가
▷ FruitBox에서 get하면 여기의 list.get()을 통해 list에 있는 거 꺼내 줌
▷ FruitBox에서 size재면 여기의 list.size()를 통해 list 사이즈 알려 줌
▷ FruitBox에서 toString하면 여기의 list.toString()를 통해 list 내용 String으로 보여 줌
class Box<T> {
ArrayList<T> list = new ArrayList<T>();
void add(T item) { list.add(item); }
T get(int i) { return list.get(i); }
int size() { return list.size(); }
public String toString() {return list.toString(); }
}
▶ 제네릭스를 사용하여 Box 객체 생성
▷ FruitBox<Fruit>
▷ FruitBox<Apple>
▷ FruitBox<Grapes>
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();
FruitBox<Grapes> grapesBox = new FruitBox<Grapes>();
▶ 생성한 Box 객체에 과일 객체 add()
class Fruit implements Eatable { public String toString() {return "Fruit";} }
interface Eatable { }
class Apple extends Fruit { public String toString() {return "Apple";} }
class Grapes extends Fruit { public String toString() {return "Grapes";} }
▷ fruitBox는 Fruit의 자손 다 가능 : Fruit, Apple, Grapes
▷ appleBox Apple만 가능 : 자손 없음
▷ fruitBox는 Grapes만 가능 : 자손 없음
fruitBox.add(new Fruit());
fruitBox.add(new Apple());
fruitBox.add(new Grapes());
appleBox.add(new Apple());
grapesBox.add(new Grapes());
▷ 전체
package baek;
import java.util.ArrayList;
class Fruit implements Eatable { public String toString() {return "Fruit";} }
interface Eatable { }
class Apple extends Fruit { public String toString() {return "Apple";} }
class Grapes extends Fruit { public String toString() {return "Grapes";} }
class Play {
public static void main(String[] args) {
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();
FruitBox<Grapes> grapesBox = new FruitBox<Grapes>();
fruitBox.add(new Fruit());
fruitBox.add(new Apple());
fruitBox.add(new Grapes());
appleBox.add(new Apple());
grapesBox.add(new Grapes());
System.out.println("fruitBox : " + fruitBox);
System.out.println("appleBox : " + appleBox);
System.out.println("grapesBox : " + grapesBox);
}
}
class FruitBox<T extends Fruit & Eatable> extends Box<T> {
}
class Box<T> {
ArrayList<T> list = new ArrayList<T>();
void add(T item) { list.add(item); }
T get(int i) { return list.get(i); }
int size() { return list.size(); }
public String toString() {return list.toString(); }
}
// console
fruitBox : [Fruit, Apple, Grapes]
appleBox : [Apple]
grapesBox : [Grapes]
▶ 왜 에러가 나는가?
// ①
FruitBox<Grape> grapeBox = new FruitBox<Apple>();
// ②
FruitBox<Toy> toyBox = new FruitBox<Toy>();
// ③
appleBox.add(new Grapes());
▷ ① Grape - Apple 타입 불일치
▷ ② Toy - Fruit을 상속 받지 않음
▷ ③ appleBox에는 Apple 객체만 가능, Grapes 객체 불가능
Ch12 - 11. 지네릭스의 제약
▶ 타입 변수에 대입은 인스턴스 별로 다르게 가능 : <>
안에 다른 타입 대입 가능
Box<Apple> appleBox = new Box<Abble>();
Box<Grapes> GrapesBox = new Box<Grapes>();
▷ static 멤버에 타입 변수 사용 불가
class Box<T> {
static T item;
static int compare(T t1, T t2) { ... } // 에러
}
▷ 배열 생성 시, 타입 변수 사용 불가
▷ 단, 타입 변수로 배열 선언은 가능
- 배열 선언
class Box<T> { T[] itemArr; // OK! T타입의 배열을 위한 참조 변수 }
- 배열 생성
class Box<T> { T[] toArray() { T[] tmpArr = new T[itemArr.length]; // ERROR! 지네릭 배열 생성 불가 } }
new
연산자 뒤에는 확실한 것만! 타입 변수처럼 바뀔 수 있는 건 안됨