본문 바로가기
Kotlin

[Kotlin] 스타 프로젝션(*)과 Any의 차이

by Nhahan 2025. 4. 3.

스타 프로젝션(List<*>) 예제

fun printList(list: MutableList<*>) {
    // 리스트의 요소를 안전하게 읽을 수 있다. 하지만 쓰기는 불가능하다. (반환 타입은 Any?로 추론)
    for (item in list) {
        println(item)
    }
}

fun main() {
    val stringList: MutableList<String> = mutableListOf("A", "B", "C")
    printList(stringList)
    
    val intList: MutableList<Int> = mutableListOf(1, 2, 3)
    printList(intList)
}

MutableList<*>는 "모든 타입의 리스트"를 받겠다는 의미지만, 구체적인 타입 정보가 없으므로 읽기 전용이다.

 

List<Any> 사용 예제

fun addElement(list: MutableList<Any>, element: Any) {
    // MutableList<Any>는 어떤 타입의 값도 추가 가능.
    list.add(element)
}

fun main() {
    val anyList: MutableList<Any> = mutableListOf(1, "문자열")
    addElement(anyList, 3.14)
    println(anyList
    
    // 하지만 MutableList<String>은 MutableList<Any>의 하위 타입이 아님.
    val stringList: MutableList<String> = mutableListOf("A", "B")
    // addElement(stringList, "C") // 컴파일 에러!
}

여기서 addElement 함수는 MutableList<Any>를 인자로 받으므로, 리스트에 어떤 타입의 값도 추가할 수 있다. 그러나 제네릭은 불공변하기 때문에, MutableList<String>은 MutableList<Any>의 하위 타입이 아니어서 호출할 수 없다.

 

정리하자면, MutableList<Any>는 명시적으로 Any를 사용하여 모든 타입의 값을 추가할 수 있지만, MutableList<*>는 타입 인자가 불명확해 읽기 전용으로만 안전하게 사용할 수 있다.

 

String은 Any의 하위 타입이다. 하지만, 제네릭 타입인 MutableList<String>은 불공변성(invariance) 때문에 MutableList<Any>의 하위 타입이 아니며, 이는 Int가 Number의 하위 타입임에도 불구하고 MutableList<Int>가 MutableList<Number>의 하위 타입이 아닌 것과 동일한 원리다.

 

반응형

댓글