0Pricing
Kotlin Academy · 강의

스타 프로젝션과 *를 사용할 때

알 수 없는 제네릭 타입에 스타 프로젝션을 적용하고 그 한계를 이해해 보세요.

스타 프로젝션과 *를 사용할 때은(는) CoddyKit의 무료 Kotlin Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Kotlin Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

스타 프로젝션이란 무엇입니까

스타 프로젝션(*)은 "타입 인수를 알 수 없는 제네릭 타입"을 나타내는 Kotlin의 방식입니다. Java의 원시 타입이나 제한되지 않은 와일드카드 <?>에 대응하는 안전한 방식입니다.

fun printList(list: List<*>) {
    for (item in list) println(item)
}
fun main() {
    printList(listOf(1, 2, 3))
    printList(listOf("a", "b"))
    printList(listOf(true, 42, "mixed"))
}

스타 프로젝션 타입에서 읽기

List<*>에서는 요소를 Any?로 읽을 수 있습니다. 실제 타입을 알 수 없으므로 요소를 추가할 수 없습니다.

fun process(list: List<*>) {
    val first: Any? = list.firstOrNull()
    println("First: $first, Size: ${list.size}")
    // list.add("x") // compile error: can't write to List<*>
}
fun main() {
    process(listOf(10, 20, 30))
}

스타 프로젝션과 out Any

List<*>와 List<out Any?>는 동등합니다. 스타 프로젝션은 상한을 사용한 공변 프로젝션의 축약형입니다.

fun sumStars(list: List<*>): Int = list.size
fun sumOut(list: List<out Any?>): Int = list.size
fun main() {
    val l = listOf(1, "two", true)
    println(sumStars(l))  // 3
    println(sumOut(l))    // 3
}

함수 매개변수의 스타 프로젝션

모든 제네릭 변형을 받아들이되 T를 알아야 하는 메서드는 호출할 필요가 없을 때 함수 시그니처에 *를 사용합니다.

fun containerInfo(map: Map<*, *>): String {
    return "keys=${map.keys.size}, values=${map.values.size}"
}
fun main() {
    val m = mapOf(1 to "one", 2 to "two")
    println(containerInfo(m))
}

MutableList에서의 스타 프로젝션

MutableList<*>에서는 Any?로 읽을 수 있지만 전혀 쓸 수 없습니다. 컴파일러가 이를 방지합니다.

fun clearFirstElement(list: MutableList<*>) {
    if (list.isNotEmpty()) {
        list.removeAt(0)  // OK: remove by index doesn't need T
        // list.add("x") // Error: can't write unknown type
    }
}
fun main() {
    val m = mutableListOf(1, 2, 3)
    clearFirstElement(m)
    println(m) // [2, 3]
}

스타 프로젝션을 사용하는 클래스

런타임에 제네릭 클래스 타입을 검사할 때는 타입 인수가 소거되므로 스타 프로젝션을 사용합니다.

fun isListOfSomething(obj: Any): Boolean {
    return obj is List<*>  // OK with star
    // obj is List<String> // Warning: cannot check erased type
}
fun main() {
    println(isListOfSomething(listOf(1, 2)))  // true
    println(isListOfSomething("not a list"))  // false
}

여러 스타 매개변수

알 수 없는 타입의 쌍이나 맵을 다룰 때 함수에 여러 스타 프로젝션 매개변수를 사용할 수 있습니다.

fun describeMap(map: Map<*, *>) {
    map.forEach { (k, v) ->
        println("${k?.javaClass?.simpleName} -> ${v?.javaClass?.simpleName}")
    }
}
fun main() {
    describeMap(mapOf("key" to 42, 1 to true))
}

스타 프로젝션을 사용하지 않을 때

컬렉션에 써야 하거나 제한된 타입 매개변수를 사용할 수 있다면 스타 프로젝션을 피합니다. 제한된 타입 매개변수가 더 많은 정보를 제공하기 때문입니다.

// Bad: loses type information
fun addToStar(list: MutableList<*>, item: Any?) {
    // list.add(item) // compile error
}
// Better: use bounded type parameter
fun <T : Any> addTyped(list: MutableList<T>, item: T) {
    list.add(item)
}
fun main() {
    val l = mutableListOf("a")
    addTyped(l, "b")
    println(l)
}

타입 검사와 캐스트에서의 스타 프로젝션

스타 프로젝션을 사용해 제네릭 클래스의 instanceof 검사를 수행한 다음, 실제 작업을 위해 특정 타입으로 캐스트합니다.

fun handleResponse(response: Any) {
    if (response is List<*>) {
        val list = response as List<*>
        println("List with ${list.size} elements")
        val first = list.firstOrNull()
        if (first is String) println("First string: $first")
    }
}
fun main() {
    handleResponse(listOf("hello", "world"))
    handleResponse(42)
}

실습: 제네릭 이벤트 디스패처

모든 Handler<*>를 받아들이면서 타입이 지정된 이벤트를 안전하게 전달하는 디스패처입니다.

interface Handler<in T> { fun handle(event: T) }
class LogHandler : Handler<Any> {
    override fun handle(event: Any) = println("Event: $event")
}
fun dispatch(handler: Handler<*>, event: Any) {
    @Suppress("UNCHECKED_CAST")
    (handler as Handler<Any>).handle(event)
}
fun main() {
    dispatch(LogHandler(), "click")
    dispatch(LogHandler(), 42)
}

reified 문맥에서의 스타 프로젝션

스타 프로젝션은 KClass<*>를 통해 런타임 타입을 검사하는 리플렉션 및 직렬화 코드에서 특히 자주 사용됩니다.

fun printClassName(klass: kotlin.reflect.KClass<*>) {
    println(klass.simpleName)
}
fun main() {
    printClassName(String::class)     // String
    printClassName(List::class)       // List
    printClassName(Int::class)        // Int
}

빠른 확인

List<*>에서 읽을 때 어떤 타입을 얻게 됩니까?

복습

스타 프로젝션(*)은 읽기 전용 접근을 위해 모든 제네릭 변형을 받아들입니다. 타입 검사, 제네릭 유틸리티, 리플렉션에 사용합니다. 컬렉션에 써야 하거나 제한된 타입 매개변수가 더 나은 타입 안전성을 제공할 때는 사용하지 않습니다.

자주 묻는 질문

“스타 프로젝션과 *를 사용할 때” 강의는 무료인가요?

네 — “스타 프로젝션과 *를 사용할 때” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Kotlin Academy 강의 전체를 잠금 해제할 수 있습니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“스타 프로젝션과 *를 사용할 때”에서 뭘 배우나요?

알 수 없는 제네릭 타입에 스타 프로젝션을 적용하고 그 한계를 이해해 보세요. 브라우저에서 직접 실행하는 실습 코드로 Kotlin Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Kotlin Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Kotlin Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“스타 프로젝션과 *를 사용할 때” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Kotlin Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Kotlin Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. where를 사용한 제네릭 함수와 타입 제약
  2. 선언 위치 변성: in과 out
  3. 스타 프로젝션과 *를 사용할 때
  4. 타입 소거와 reified 타입 매개변수
← Kotlin Academy(으)로 돌아가기