공변과 반공변
자바 개발자라면 제네릭 타입의 와일드카드 ? extends T, ? super T를 다뤄본 적 있을 거예요.
코틀린에서는 이 개념을 out과 in 키워드로 표현합니다.
이번 글에서는 공변성(Covariance)과 반공변성(Contravariance)에 대해 쉽고 간결하게 설명하겠습니다.
📘 공변성 (Covariance) - out
공변이란, 타입 파라미터의 상속 관계가 제네릭 클래스까지 이어지는 것을 의미합니다.out T는 읽기 전용(Generic Producer)입니다.T 타입의 값을 반환(return)할 수는 있지만, 넣을 수는 없습니다.
class Cage<T> {
private val animals: MutableList<T> = mutableListOf()
fun getFirst(): T {
return animals.first()
}
fun moveFrom(otherCage: Cage<out T>) {
this.anumals.addAll(otherCage.animals)
}
}
fun main() {
val goldFishCage = Cage<GoldFish>()
goldFishCage.put(GoldFish("금붕어"))
val cage = Cage<Fish>()
cage.moveFrom(goldFishCage)
val fish: Fish = cage.getFirst() // 읽기 가능
}
📕 반공변성 (Contravariance) - in
반공변이란, 타입 파라미터의 상속 관계가 제네릭 클래스까지 반대로 이어지는 것을 의미합니다.in T는 쓰기 전용(Generic Consumer)입니다.T 타입의 값을 넣을 수는 있지만, 꺼낼 수는 없습니다.
class Cage<T> {
private val animals: MutableList<T> = mutableListOf()
fun getFirst(): T {
return animals.first()
}
fun put(animal: T) {
this.animals.add(animal)
}
fun moveFrom(otherCage: Cage<out T>) {
this.anumals.addAll(otherCage.animals)
}
fun moveTo(otherCage: Cage<in T>) {
otherCage.anumals.addAll(this.animals)
}
}
fun main() {
val fishCage = Cage<Fish>()
val goldFishCage = Cage<GoldFish>()
goldFishCage.put(GoldFish("금붕어"))
goldFishCage.moveTo(fishCage) // goldFishCage를 모두 fishCage로 옮겨라!
}
✅ 공변과 반공변, 이렇게 기억하세요!
| 구분 | 키워드 | 타입 변환 방향 | 역할 | 특징 |
| 공변성 | out | 자식 → 부모로 변환 | Producer | 읽기 전용 ✅ |
| 반공변성 | in | 부모 → 자식로 변환 | Consumer | 쓰기 전용 ✅ |
더보기
참고로 코틀린에서는 변성을 주는 위치를 클라스 자체에 붙일 수 있고, 함수 또는 변수에만 붙일 수도 있습니다.