ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 아이템31. 한정적 와일드카드를 사용해 API 유연성을 높이라
    Java/이펙티브 자바 2023. 10. 31. 16:32

    핵심정리 - Chooser와 Union API 개선

    PECS : Producer-Extends, Consumer-Super

    - Producer-Extends

        ㆍObject의 컬렉션 Number나 Integer를 넣을 수 있다.

        ㆍNumber의 컬렉션에 Integer를 넣을 수 있다.

    - Consumer-Super

        ㆍInteger의 컬렉션의 객체를 꺼내서 Number의 컬렉션에 담을 수 있다.

        ㆍNumber나 Integer의 컬렉션의 객체를 꺼내서 Object의 컬렉션에 담을 수 있다.

     

    - 예시)

    // 코드 31-2 E 생산자(producer) 매개변수에 와일드카드 타입 적용 (182쪽)
    public void pushAll(Iterable<? extends E> src) {
        for (E e : src) {
            push(e);
        }
    }

        ㆍNumber 라면 Integer, Double 등등 이 들어갈 수 있다.
        ㆍ즉, 하위 타입으로 확장 가능하다. ( 최상위 타입이 한정되어 있으므로 상위 한정 )

    // 코드 31-4 E 소비자(consumer) 매개변수에 와일드카드 타입 적용 (183쪽)
    public void popAll(Collection<? super E> dst) {
        while(!isEmpty()) {
            dst.add(pop());
        }
    }

        ㆍNumber 라면 Object Collection 안에 값을 넣을 수 있다.

        ㆍ즉, 상위 타입으로 확장 가능하다. ( 최하위 타입이 한정되어 있으므로 하위 한정 )

     

    핵심정리 - Comparator 와 Comparable 은 소비자

    - Comparable을 직접 구현하지 않고, 직접 구현한 다른 타입을 확장한 타입을 지원하려면 와일드카드가 필요하다.

        ㆍScheduledFuture → Delayed → Comparable<T>

        ㆍScheduledFuture는 Comparable을 직접 구현하지 않았지만, 그 상위 타입(Delayed)이 구현하고 있다.

     

    - Producer - extends

    public Chooser(Collection<? extends T> choices) {
        chiceList = new ArrayList<>(choices);
    }
        
    public static void main(String[] args) {
        List<Integer> intList = List.of(1,2,3,4,5,6);
        Chooser<Number> chooser = new Chooser<>(intList);
    }
    public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2) {
        Set<E> result = new HashSet<>(s1);
        result.addAll(s2);
        return result;
    }
    
     public static void main(String[] args) {
        Set<Integer> integers = new HashSet<>();
        integers.add(1);
        integers.add(3);
        integers.add(5);
    
        Set<Double> doubles = new HashSet<>();
        doubles.add(2.0);
        doubles.add(4.0);
        doubles.add(6.0);
    
        Set<Number> numbers = union(integers, doubles);
    }

     

    - Consumer - super

    public static <E extends Comparable<? super E>> E max(List<? extends E> list) {
    	...
    }
    
    public static void main(String[] args) {
        List<IntegerBox> list = new ArrayList<>();
        list.add(new IntegerBox(1, "phm"));
        list.add(new IntegerBox(2, "phm2"));
    
        System.out.println(max(list));
    }

        ㆍIntegerBox는 Comparable을 구현하지 않았다. 하지만 상속하는 Box가 Comparable을 구현했기에 사용가능

     

    핵심정리 - 와일드카드 활용 팁

    - 메서드 선언에 타입 매개변수가 한 번만 나오면 와일드카드로 대체하라

        ㆍ한정적 타입이라면 한정적 와일드카드로

        ㆍ비한정적 타입이라면 비한정적 와일드카드로

    - 주의!

        ㆍ비한정적 와일드카드(?)로 정의한 타입에는 null을 제외한 아무것도 넣을 수 없다.

     

     

    - E, T 같은 경우는 특정한 타입, ? 같은 경우는 불특정한 임의의 타입

    Box<?> myBox = new IntegerBox(10, "phm");
    myBox.change(100);	//컴파일에러 - myBox가 무슨 타입인지 모르기때문

     

    public static <E> void swap(List<E> list, int i, int j) {
    //    public static void swap(List<?> list, int i, int j) {
    	 list.set(i, list.set(j, list.get(i)));
    //        swapHelper(list, i, j);
    }

        ㆍ꺼내는건 가능하지만 넣는건 null 말고는 불가능

        ㆍ그렇기에 Helper 메서드를 쓸바에 위와 같은 방식 추천

     

     

    완벽공략 - 타입추론

    - 타입을 추론하는 컴파일러의 기능

    - 모든 인자의 가장 구체젝인 공통 타입 (most specific type)

    - 제네릭 메서드와 타입 추론 : 메서드 매개변수를 기반으로 타입 매개변수를 추론할 수 있다.

    - 제네릭 클래스 생성자를 호출할 때 다이아몬드 연산자 <>를 사용하면 타입을 추론한다.

    ArrayList<Box<Integer>> listOfIntegerBoxes = new ArrayList<>();
    
    List<String> stringlist = Collections.emptyList();
    List<Integer> integerlist = Collections.emptyList();

     

    - 자바 컴파일러는 "타겟 타입"을 기반으로 호출하는 제네릭 메서드의 타입 매개변수를 추론한다.

        ㆍ자바 8에서 "타겟 타입"이 "메서드의 인자"까지 확장되면서 이전에 비해 타입 추론이 강화되었다.

    댓글

Designed by Tistory.