지네릭스의 장점
1. 타입 안정성을 제공한다.
2. 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해 진다.
- 의도하지 않은 타입의 객체가 저장되는 것을 막음
- 저장된 객체를 꺼내올 때 원래의 타입과 다른 타입으로 잘못 형변환되어 발생할 수 있는 오류를 줄여줌
class Box{
Object item;
void setItem(Object item) {this.item = item;}
Object getItem(){return item;}
}
class Box<T>{ // 지네릭 타입 T를 선언
T item;
void setItem(T item) { this.item = item;}
T getItem() { return item;}
}
Box<String> b = new Box<String>(); //타입 T 대신, 실제 타입을 지정
b.setItem(new Object()); //에러, String이외의 타입은 지정불가
b.setItem("ABC"); //Ok. String타입이므로 가능
String item = (String) b.getItem(); // 형변환이 필요없음
Box b = new Box(); // OK. T는 Object로 간주된다.
b.setItem("ABC"); // 경고. unchecked or unsafe operation
b.setItem(new Object()); // 경고. unchecked or unsafe operation
Box<Object> b = new Box<Object>();
b.setItem("ABC"); //경고발생 안함
b.setItem(new Object()); // 경고발생 안함
Box 지네릭 클래스. ‘T의 Box’ 또는 ‘T Box’라고 읽는다.
T 타입 변수 또는 타입 매개변수.(T는 타입 문자)
Box 원시 타입(raw type)
class Box<T>{
static T item; // 에러
static int compare(T t1, T t2){...} // 에러
...
}
class Box<T>{
T[] itemArr; // OK. T타입의 배열을 위한 참조 변수
...
T[] toArray(){
T[] tmpArr = new T[itemArr.length]; // 에러. 지네릭 배열 생성불가
...
return tmpArr;
}
...
}
Box<Apple> appleBox = new Box<Apple>(); // OK
Box<Apple> appleBox = new Box<Grape>(); // 에러
Box<Apple> appleBox = new FruitBox<Apple>(); // OK. 다형성
Box<Apple> appleBox = new Box<Apple>();
Box<Apple> appleBox = new Box<>(); // OK. JDK1.7부터 생략가능
Box<Apple> appleBox = new Box<Apple>();
appleBox.add(new Apple()); // Ok.
appleBox.add(new Grape()); // 에러. Box<Apple>에는 Apple객체만 추가가능
Box<Fruit> fruitBox = new Box<Fruit>();
fruitBox.add(new Fruit()); //OK
fruitBox.add(new Apple()); //Ok. void add(Fruit item)
import java.utilArrayList;
class Fruit { public String toString(){return "Fruit";}}
class Apple extends Fruit { public String toString() {return "Apple";}}
class Grape extends Fruit { public String toString() {return "Grape";}}
class Toy { public String toString() {return "Toy";}}
class FruitBoxEx1 {
public sttic void main(String[] args) {
Box<Fruit> fruitBox = new Box<Fruit>();
Box<Apple> appleBox = new Box<Apple>();
Box<Toy> toyBox = new Box<Toy>()
// Box<Grape> grapeBox = new Box<Apple>(); // 에러. 타입 불일치
fruitBox.add(new Fruit());
fruitBox.add(new Apple()); // OK. void add(Fruit item)
appleBox.add(new Apple());
appleBox.add(new Apple());
// appleBox.add(new Toy()); // 에러. Box<Apple>에는 Apple만 담을 수 있음
toyBox.add(new Toy());
toyBox.add(new Apple()); // 에러. Box<Toy> 에는 Apple을 담을 수 없음
System.out.println(fruitBox);
System.out.println(appleBox);
System.out.println(toyBox);
} // main의 끝
}
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();}
}
class FruitBox<T extends Fruit> { // Fruit의 자손만 타입을 지정가능
ArrayList<T> list = new ArrayList<T>();
...
}
FruitBox<Apple> appleBox = new FruitBox<Apple>(); // OK
FruitBox<Toy> toyBox = new FruitBox<Toy>(); // 에러. Toy는 Fruit의 자손이 아님
interface Eatable{}
class FruitBox<T extends Eatable>{ ... }
class FruitBox<T extends Fruit & Eatable>{...}
설명대박!