[effective java] (8) 한정적 와일드 카드를 사용해 API 유연성을 높혀라

orca·2022년 11월 17일
0

effective java

목록 보기
8/8

Bounded Wildcard

와일드카드는 컴퓨터에서 특정 명령어로 명령을 내릴 때, 여러 파일을 한꺼번에 지정할 목적으로 사용하는 기호를 가리킨다.
예를 들어 cmd에서 a*는 a로 시작하는 모든 글자를 의미하며, 이와 비슷한 a+는 a를 제외한 모든 a로 시작하는 문자열로 치환된다.

Bounded Wildcard는 파라미터에 대한 제한을 느슨하게 하기 위해 사용된다.

ex>
? extends E : 파라미터로 받을 E의 확장 클래스를 허용
? super E : 파라미터로 받을 E의 부모 클래스를 허용

공변과 불공변

불공변 (invariant) : 상속 관계에 상관없이 자신의 타입만 허용하는 것 ex> 제네릭
공변 (covariant) : 자신의 타입과 자신을 상속한 하위 클래스를 허용하는 것 ex> 배열

한정적 와일드 카드 활용 예시

아래와 같이 제네릭 클래스가 있다고 가정하자
💬개발자의 의도 :
Integer, Long, Double 등의 박싱 타입은 Number의 확장이니까 Stack<Number> 객체를 만들면, pushAllIterable<Integer>를 넘겨줘도 되겠지 ?

public class Stack<E> {
    public static final int DEFAULT_SIZE = 20;
    private int size;
    private E[] elements;

    public Stack(){
        elements = (E[]) new Object[DEFAULT_SIZE]; // object를 Element로 캐스팅
        size = 0;
    }

    public E push(E item){
        elements[++size] = item;
        return item;
    }


    public void pushAll(Iterable<E> src){
        for(E e:src){
            push(e);
        }
    }

    public static void main(String[] args) {
        Stack<Number> numberStack = new Stack<>();
        Iterable<Integer> integers = List.of(1,2);
        numberStack.pushAll(integers);
    }
}

그러나 컴파일 에러가 발생함

제네릭은 불공변이기 때문

이럴 때 한정적 와일드 카드를 사용하면 됨

pushAll의 매개변수를 Iterable<? extends E> src로 변경해서 E를 확장한 타입을 모두 허용
ex> Integer가 Number를 확장했으므로,Iterable<Integer>는 pushAll의 매개 변수로 들어갈 수 있음

public class Stack<E> {
    public static final int DEFAULT_SIZE = 20;
    private int size;
    private E[] elements;

    public Stack(){
        elements = (E[]) new Object[DEFAULT_SIZE]; // object를 Element로 캐스팅
        size = 0;
    }

    public E push(E item){
        elements[++size] = item;
        return item;
    }


    public void pushAll(Iterable<? extends E> src){
        for(E e:src){
            push(e);
        }
    }

    public static void main(String[] args) {
        Stack<Number> numberStack = new Stack<>();
        Iterable<Integer> integers = List.of(1,2);
        numberStack.pushAll(integers);
    }
}

0개의 댓글