Raw Type의 슈퍼 클래스는 Raw Type이다. 상속 받지 않은 Raw Type의 생성자, 인스턴스 메서드, 인스턴스 필드는 Raw Type이다.

Generic Classes: Cases

class Shape { } //Raw Type
class FruitBox<T> extends Shape { } //Generic Type

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 Box<T> { } // 이와 같이 generic class를 상속 받을 수 있다.

class Box<T> { ... }
class FruitBox<T extends Fruit> extends Box<T> { }

위와 같이 기능은 Box에 있는 곳을 상속 받되, 내부에 들이는 객체의 자료형은 Fruit로 제한할 수 있다.

class Box<T extends Fruit> { ... }
class FruitBox<T> extends Box<T> { ... } // Error

위와 같이 Box 클래스는 Fruit로 제한을 걸어 두었으나 FruitBox는 Box를 상속받으면서도 Fruit를 제한하지 않았다.

class Box<T extends Fruit> { ... }
class FruitBox<T extends Fruit> extends Box<T> { ... } // OK

Generic Classes: Wild Card

class Juicer {
	static Juice makeJuice(FruitBox<Fruit> box) {
		String tmp = "";
		for(Fruit f : box.getList()) tmp += f + " ";
		return new Juice(tmp);
	}
}

위와 같이 생긴 클래스가 있다고 가정하자. 여기에서 box.getList()는 ArrayList로 작성된 FruitBox 에서 리스트를 반환하는 함수이다.

더 자세한 클래스와 코드에 대한 설명은 이후에서 다루도록 하겠다.

FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();
fruitBox = new FruitBox<Fruit>();
appleBox = new FruitBox<Apple>();
System.out.println(Juicer.makeJuice(fruitBox)); // OK
System.out.println(Juicer.makeJuice(appleBox)); // Error: the argument is not of type FruitBox<Fruit>.

이제 중요한 것은 위와 같이 작성하였을 때 appleBox를 집어넣은 곳에서 에러가 난다. 왜냐하면 Juicer에서 파라미터로 FruitBox<Furit>을 받기로 하였기 때문이다.

그래서 코드를 다음과 같이 바꾸면 어떻게 될까?