Effective Java : 아이템31. 완벽공략 44. 타입추론

    들어가기 전

    • 이 글은 인프런 백기선님의 강의를 복습하며 작성한 글입니다.

    이 글의 요약

    • 좌측 항에 타입이 명확히 선언되어 있으면, 우측 항에서는 <> 연산자를 이용하면 타입 추론이 가능해진다. 
    • 메서드의 매개변수가 제네릭일 경우, 메서드 매개변수에 전달되는 인자의 타입에 따라 메서드의 제네릭 타입이 추론 가능해진다.
    • 메서드 매개변수에 전달되는 인자의 타입으로 메서드 제네릭 타입이 추론된다면, 반환되는 타입이 어떠한 타입인지 따로 명시할 필요가 없다. BoxExample.<Hello>add() 같은 곳에서 <Hello> 생략 가능하다. 
    • 메서드 인자로 List<E> 같은 제네릭 타입이 전달되는 경우, 메서드에 구체적인 타입이 선언되어있으면 그 타입으로 타입 추론이 가능해진다. 

    완벽 공략 44. 타입 추론 (Type Inference)

    • 타입추론은 타입을 추론하는 컴파일러의 기능
    • 모든 인자의 가장 구체적인 공통 타입 (most specific type)으로 추론한다.
    • 제네릭 메서드와 타입 추론 
      • 메서드 매개변수를 기반으로 타입 매개변수<E>를 추론할 수 있다.
    • 제네릭 클래스 생성자를 호출할 때 다이아몬드 연산자 <>를 사용하면 타입을 추론한다. 
    • 자바 컴파일러는 '타겟 타입'을 기반으로 호출하는 제너릭 메서드의 타입 매개변수를 추론한다
      • 자바 8에서 '타겟 타입'이 '메서드의 인자'까지 확장되면서 이전에 비해 타입 추론이 강화되었다. 

    이 글에서는 자바 컴파일러가 제공하는 타입 추론에 대해서 공부해보고자 한다. 자바에서는 타입 추론을 여러 형태로 추론하기 때문에 편리하게 사용할 수 있다. 


    타입 추론

    타입 추론은 개발자가 어떤 타입을 사용하는지 명시하지 않아도, 자바 컴파일러가 어떤 타입을 쓸지 추론해서 적절한 타입을 넣어주는 것이다.


    각종 타입 추론

    1. 왼쪽에 ArrayList<Box<Integer>가 존재한다. 이 때, 오른쪽은 <> 연산자를 이용해서 생성하면, 컴파일러가 자동으로 타입추론 해준다.
    2. addBox()는 한정 타입변수 <U>를 사용한다. 이 U는 매개변수로 전달되는 값을 보고 추론한다. 10이 전달되었기 때문에 U는 Integer로 추론된다. 
    3. 매개변수에서 전달된 값으로 충분히 <U>의 타입이 추론되면 리턴 변수의 타입을 의미하는 BoxExample.<Integer>addBox()에서 <Integer>는 생략해도 된다. 이것을 Type Witeness라 하는데, 매개변수를 통해 타입 추론이 완료되었기 때문에 따로 <U>를 정의해 줄 필요가 없다.
    4. Collections.emptyList()는 List<T>를 반환한다. 이 때 <T>는 좌측 항에 있는 String, Integer 타입을 보고 추론한다.

     

    private static <U> void addBox(U u, List<Box<U>> boxes) {
        Box<U> box = new Box<>();
        box.set(u);
        boxes.add(box);
    }
    
    private static void processStringList(List<String> stringList) {
    
    }
    
    public static void main(String[] args) {
        // <> 연산자를 이용하면 컴파일러가 타입을 추론해서 생성한다.
        ArrayList<Box<Integer>> listOfIntegerBoxes = new ArrayList<>();
    
        // 메서드 매개변수로 충분히 제네릭 타입을 추론할 수 있다. 따라서 반환 타입은 생략해도 된다.
        BoxExample.<Integer>addBox(10, listOfIntegerBoxes);
        BoxExample.addBox(20, listOfIntegerBoxes);
        BoxExample.addBox(30, listOfIntegerBoxes);
        BoxExample.outputBoxes(listOfIntegerBoxes);
    
        // Target Type
        List<String> stringList = Collections.emptyList(); // 좌측 타입을 보고 추론
        List<Integer> integerList = Collections.emptyList(); // 좌측 타입을 보고 추론
        BoxExample.processStringList(Collections.emptyList()); // 매개변수가 <String>인 것을 보고 추론
    }

     

     

    메서드의 타입을 보고도 타입 추론 가능

    전달되는 메서드의 타입을 보고도 타입 추론이 가능하다.

    1. Collections.emptyList()는 List<T> 타입을 반환한다. main() 메서드에서는 Collection.emptyList()의 <T>를 추론할 수 없다. 
    2. List<T>는 processStringList() 메서드에 전달된다. 이 때, processStringList의 인자는 List<String>이다. 여기서 <T>는 <String>이 된다.

    따라서 Collections.emptyList()의 List<T>는 List<String>으로 추론된다. 이 말은 메서드에 전달되는 매개변수의 타입으로 메서드의 타입을 추론하는 것도 있지만, 메서드의 매개변수 타입 정의가 무엇인지에 따라 외부에서 전달되는 제네릭 인자의 타입도 추론이 가능해진다. 

    // Collection.java
    public static final <T> List<T> emptyList() {
            return (List<T>) EMPTY_LIST;
        }
    
    
    // BoxExample.java
    private static void processStringList(List<String> stringList) {
    	...
    }
    
    
    // BoxExample.java
    public static void main(String[] args) {
        BoxExample.processStringList(Collections.emptyList()); // 매개변수가 <String>인 것을 보고 추론
    }

     

     

    댓글

    Designed by JB FACTORY