Skip to content

공변성과 반공변성

Published: at 오전 11:01

Table of contents

Open Table of contents

변성

변성(variance)는 List<String>List<Any>와 같이 기저 타입이 같고 타입 인자가 다른 경우에 서로 어떤 관계를 가지는지를 설명합니다. 즉, 변성은 서브타입 관계가 있는지 설명하는 개념입니다.

변성을 잘 활용하면 사용에 불편하지 않으면서 타입 안정성을 보장하는 API를 만들 수 있습니다.

제네릭 클래스가 아닌 클래스에서는 클래스 이름을 바로 사용하여 타입을 지정할 수 있습니다.

class Box(val value: Int)

val box: Box = Box(1) // Box 타입

하지만 제네릭 클래스에서는 구체적인 타입 인자를 지정해야 합니다. 예를 들어 List 클래스는 제네릭 클래스이고 List<String>List<Int>와 같이 타입 인자를 지정하여 타입을 만들어야 합니다.

class Box<T>(val value: T)

val box: Box<Int> = Box(1) // Box<Int> 타입

공변성(covariance)

공변성은 서브타입 관계가 유지되는 것을 의미합니다. 예를 들어, List가 공변적이라면 List<String>List<Any>의 서브타입이 됩니다. 코틀린에서는 out 키워드를 사용하여 공변성을 지정할 수 있습니다.

open class Animal {
    fun feed() {
        println("feed")
    }
}

class Cat : Animal() {
    fun meow() {
        println("meow")
    }
}

class Dog : Animal() {
    fun bark() {
        println("bark")
    }
}

class Cage<out T : Animal>(val animal: T)

fun main() {
    val catCage: Cage<Cat> = Cage(Cat())
    val dogCage: Cage<Dog> = Cage(Dog())

    val animalCage: Cage<Animal> = catCage
    animalCage.animal.feed()
}

Cage 클래스는 T 타입의 동물을 담는 클래스입니다. out 키워드가 사용된 타입은 메소드 내에서 T 타입의 값을 생산할 수 있습니다. 따라서 Cage<Cat>Cage<Animal>의 서브타입이 됩니다.

out 키워드는 또한 반환 타입이나 프로퍼티의 타입에서만 메소드 사용을 허용하여 하위 타입관계의 안전성을 보장합니다.

반공변성(contravariance)

반공변성은 슈퍼타입 관계가 유지되는 것을 의미하며 공변성의 반대 개념입니다. 코틀린에서는 in 키워드를 사용하여 반공변성을 지정할 수 있습니다.

interface Comparable<in T> {
    operator fun compareTo(other: T): Int
}

fun demo(x: Comparable<Number>) {
    x.compareTo(1.0) // 1.0은 Number의 서브타입입니다.
}

fun main() {
    val x = object : Comparable<Number> {
        override fun compareTo(other: Number): Int = 0
    }
    demo(x)
}

Comparable 인터페이스는 T 타입의 값을 비교하는 compareTo 함수를 가지고 있습니다. in 키워드가 사용된 타입은 메소드 내에서 T 타입의 값을 소비할 수 있습니다.

공변성반공변성무공변성
List<out T>Comparator<in T>MutableList<T>
타입 인자의 하위 타입 관계가 제네릭 타입에서도 유지된다.타입 인자의 하위 타입 관계가 제네릭 타입에서는 뒤집힌다.하위 타입 관계가 성립하지 않는다.
List은 List의 하위 타입이다.Comparator는 Comparator의 하위 타입이다.
T를 아웃 위치에서만 사용할 수 있다.T를 인 위치에서만 사용할 수 있다.T를 아무 위치에서나 사용할 수 있다.

참고