제네릭 클래스와 상속, 와일드 카드

gustjtmd·2022년 1월 10일
0

Java

목록 보기
18/40
제네릭 클래스도 상속이 가능하다.
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()); //넣는것 이것도 가능. 컴파일 오류 X
    }
    public static void inBox(Box7<Toy> box, Toy n){
        box.set(n);
        Toy myToy = box.get();  //꺼내는 법도 가능. 컴파일 오류 X
    }
}
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);
//      box.set(new Toy()); 넣는것 에러
    }
}
-----------------------------------------------------------------
Car를 인자로 받을수 있는 메소드에 부모 클래스의 Toy 인스턴스가 불가능한데
그럴 가능성이 생겨버려서 컴파일러 과정에서 에러가 발생한다.
정리
Box<? extends Toy> box 
대상으로 넣는것(set) 불가능!!
꺼내는것 (get)만 가능!!
하한 제한의 목적
class Plastic{...}
class Toy extends Plastic{
    @Override
    public String toString(){
        return "I am Toy";
    }
}
class BoxHandler{
//Box<Toy> 또는 Box<Plastic> 인스턴스가 인자로 전달될 수 있다.
    public static void inBox(Box7<? super Toy> box, Toy n){
        box.set(n);
 //     Toy myToy = box.get();  꺼내는 법 에러
    }
}
------------------------------------------------------------
만약 box.get에서 toy가 전달되면 상관없지만
Plastic올 경우 자식 클래스인 ToyPlastic을 인자로 받을수 없으니 컴파일 오류가 발생.
// Toy myToy = new Plastic(); 
정리
Box<? super Toy> box
대상으로 꺼내는 것(get) 불가능!
넣는것(set)만 가능!

제한된 와일드 카드 선언을 갖는 제네릭 메소드
//Toy 클래스를 담은 상자를 기준으로 inBox, outBox 메소드를 정의하였다.
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 {...}
profile
반갑습니다

0개의 댓글