제네릭 클래스도 상속이 가능하다.
class Box<T>{
protected T ob;
public void set(T o ){ob = o;}
public T get(){return ob;}
}
class SteelBox<T> extends Box<T>{
public SteelBox(T o){
ob = o;
}
}
public class GenericInheritance {
public static void main(String[] args) {
Box<Integer> iBox = new SteelBox<>(7959);
Box<String> sBox = new SteelBox<>("Simple");
System.out.println(iBox.get());
System.out.println(sBox.get());
}
}
Box<T>의 상속하는 하위 클래스를 통하여
------------------------------------------------
class SteelBox<T> extends Box<T>{
public SteelBox(T o){
ob = o;
}
}
box<T>의 참조변수로 SteelBox<T> 인스턴스를 참조하는 문장을 구성할수 있게 되었다.
--------------------------------------------------
Box<Integer> iBox = new SteelBox<>(7959);
Box<String> sBox = new SteelBox<>("Simple");

와일드카드 선언
public static void peekBox(Box<?> box{...}
제네릭 메소드와 와일드 카드 메소드의 차이
public static <T> void peekBox(Box<T> box{...}
public static void peekBox(Box<?> box{...}
--------------------------------------------------
사실 기능적인 측면에서 보면 두 메소드는 완전히 동일하다
즉 제네릭 메소드와 와일드카드 기반 메소드는 상호 대체 가능한 측면이있다.
그러므로 코드가 조금 더 간결해지니 와일드카드 메소드를 선호하자.
와일드카드의 상한과 하한의 제한
상한 제한된 와일드카드
public static void peekBox(Box<? extends Number> box{...}
-------------------------------------------------------
Number이거나 Number를 상속하는 클래스들만 가능하다.
하한 제한된 와일드카드
public static void peekBox(Box<? super Integer> box{...}
--------------------------------------------------------
Integer가 상속하는 클래스들만 가능하다.
위 메소드의 인자로 전달될수 있는 인스턴스의 타입 종류는
Box<Integer>, Box<Number>, Box<Object>로 제한된다.
Number를 상속하는 Box<Double>, Box<Boolean> X
와일드카드 제한의 이유
class Box7<T>{
private T ob;
public void set(T o){ob = o;}
public T get(){return ob;}
}
class Toy{
@Override
public String toString(){
return "I am Toy";
}
}
class BoxHandler{
public static void outBox(Box7<Toy> box){
Toy t = box.get();
System.out.println(t);
box.set(new Toy());
}
public static void inBox(Box7<Toy> box, Toy n){
box.set(n);
Toy myToy = box.get();
}
}
public class BoundedWildcardBase {
public static void main(String[] args) {
Box7<Toy> box = new Box7<>();
BoxHandler.inBox(box,new Toy());
BoxHandler.outBox(box);
}
}
상한 제한의 목적
class Toy{
@Override
public String toString(){
return "I am Toy";
}
}
class Car extends Toy{}
class BoxHandler{
public static void outBox(Box7<? extends Toy> box){
Toy t = box.get();
System.out.println(t);
}
}
-----------------------------------------------------------------
Car를 인자로 받을수 있는 메소드에 부모 클래스의 Toy 인스턴스가 불가능한데
그럴 가능성이 생겨버려서 컴파일러 과정에서 에러가 발생한다.
정리
Box<? extends Toy> box
대상으로 넣는것(set) 불가능!!
꺼내는것 (get)만 가능!!
하한 제한의 목적
class Plastic{...}
class Toy extends Plastic{
@Override
public String toString(){
return "I am Toy";
}
}
class BoxHandler{
public static void inBox(Box7<? super Toy> box, Toy n){
box.set(n);
}
}
------------------------------------------------------------
만약 box.get에서 toy가 전달되면 상관없지만
Plastic올 경우 자식 클래스인 Toy가 Plastic을 인자로 받을수 없으니 컴파일 오류가 발생.
정리
Box<? super Toy> box
대상으로 꺼내는 것(get) 불가능!
넣는것(set)만 가능!
제한된 와일드 카드 선언을 갖는 제네릭 메소드
class BoxHandler{
public static void outBox(Box<? extends Toy> box){
Toy t = box.get();
System.out.println(t);
}
public static void inBox(Box<? super Toy> box, Toy n){
box.set(n);
}
}
class Robot{
public String toString(){return "I am a Robot";}
}
----------------------------------------------------------
그리고 Box<Robot>의 인스턴스를 대상으로 outBox와 inBox메소드를 호출하고 싶다고
가정하였을때 오버로딩 메소드를 정의해보자.
class BoxHandler{
public static void outBox(Box<? extends Toy> box){...}
public static void outBox(Box<? extends Robot> box){...}
public static void inBox(Box<? extends Toy> box, Toy n){...}
public static void inBox(Box<? extends Robot> box, Robot n){...}
}
------------------------------------------------------------
public static void outBox(Box<? extends Toy> box){...}
public static void outBox(Box<? extends Robot> box){...}
오버로딩 되지 않는 이유는
제네릭 등장 이전에 정의된 클래스들과의 상호 호환성 유지를 위해
Box<?extends Toy> box -> Box box
Box<?extends Robot> box -> Box box
로 컴파일러가 지워버린다.
그러면 Box<Toy> 인스턴스와 Box<Robot>인스턴스를 동시에 inBox, OutBox
메소드를 정의하려면 어떻게 해야할까? 제네릭 메소드를 활용하면 가능하다.
public static <T> void outBox(Box<? extends T>box {...}