자바에서는 파라미터화한 타입이 파라미터 타입에 대해 무공변성이다. 즉, AB의 부모 타입이라 하더라도 List<A>List<B> 사이에는 아무런 부모 자식 타입 관계가 성립하지 않는다. 따라서 List<A>List<B>는 컴파일 시점에 전혀 다른 두 가지 타입이다(그리고 런타임에는 두 타입이 같다). 무공변성 타입의 문제는 다음과 같은 코드를 작성할 수 없다는 데 있다.

    fun <T> addAll(list1: MutableList<T>,
                   list2: MutableList<T>) {
        for (elem in list2) list1.add(elem)
    }
    
    val ls = mutableListOf("A String")
    val la: MutableList<Any> = mutableListOf()
    addAll(la, ls) // <-- 컴파일되지 않음

    String 타입의 elemList<Any>에 추가될 수 있으며, 그렇게 해도 아무 문제가 없다. 코틀린에서는 MutableList<Any>MutableList<String>을 동시에 MutableList<T>라는 제네릭 타입에 일치시킬 수 없다. 이 제네릭 함수가 제대로 작동하게 하려면 MutableList<Any>MutableList<String>의 상위 타입처럼 쓰일 수 있음을 컴파일러에 알려줘야 한다. 여기서 MutableList<Any>MutableList<String>의 상위 타입으로 쓰일 수 있는 이유는 la에서 값을 가져오기만 하고(out), 값을 넣는 일은 결코 없기 때문이다(in). 다음 코드와 같이 out이라는 한정자(qualifier)를 써서 이를 표현한다.

    신간 소식 구독하기
    뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.