0Pricing
Kotlin Academy · Lezione

Star projection e quando usare *

Applichi la star projection ai tipi generici sconosciuti e ne comprenda i limiti.

Star projection e quando usare * è una lezione Kotlin Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Kotlin Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Kotlin Academy include 4 lezioni in totale.

Cos'è la star projection?

La star projection (*) è il modo in cui Kotlin indica «un tipo generico con un argomento di tipo sconosciuto». È l'equivalente sicuro del raw type di Java o della wildcard non delimitata <?>.

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"))
}

Lettura da tipi con star projection

Da una List<*> è possibile leggere gli elementi come Any?. Non è possibile aggiungere elementi perché il tipo effettivo è sconosciuto.

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))
}

Star projection e out Any

List<*> e List<out Any?> sono equivalenti. La star projection è una forma abbreviata della proiezione covariante con il limite superiore.

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
}

Star nei parametri delle funzioni

Utilizzi * nelle firme delle funzioni quando deve accettare qualsiasi variante generica, ma può chiamare soltanto metodi che non richiedono di conoscere 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))
}

Star con MutableList

Per MutableList<*>, è possibile leggere come Any?, ma non scrivere in alcun modo: il compilatore lo impedisce.

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]
}

Classe con star projection

Quando controlla a runtime il tipo di una classe generica, utilizzi la star projection perché gli argomenti di tipo vengono cancellati.

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
}

Più parametri star

Una funzione può avere più parametri con star projection quando lavora con coppie o mappe di tipi sconosciuti.

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))
}

Quando NON usare la star projection

Eviti la star projection quando deve scrivere in una raccolta o quando può usare invece un parametro di tipo con limite: quest'ultimo fornisce più informazioni.

// 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)
}

Star con controlli e cast dei tipi

Utilizzi la star projection per eseguire controlli instanceof sulle classi generiche, quindi esegua il cast a un tipo specifico per il lavoro effettivo.

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)
}

Pratica: dispatcher generico di eventi

Un dispatcher che accetta qualsiasi Handler<*>, ma distribuisce gli eventi tipizzati in modo sicuro.

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)
}

Star nei contesti reified

La star projection è particolarmente comune nel codice di reflection e serializzazione, dove il tipo a runtime viene ispezionato tramite KClass<*>.

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

Verifica rapida

Quale tipo si ottiene leggendo da una List<*>?

Riepilogo

La star projection (*) accetta qualsiasi variante generica per l'accesso in sola lettura. La utilizzi per i controlli dei tipi, le utility generiche e la reflection. La eviti quando deve scrivere in una raccolta o quando un parametro di tipo con limite offre una migliore sicurezza dei tipi.

Domande Frequenti

La lezione «Star projection e quando usare *» è gratuita?

Sì — il testo completo di «Star projection e quando usare *» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Kotlin Academy, passa a CoddyKit PRO. Il corso Kotlin Academy include 4 lezioni in totale.

Cosa imparerò in «Star projection e quando usare *»?

Applichi la star projection ai tipi generici sconosciuti e ne comprenda i limiti. Eserciti Kotlin Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Kotlin Academy?

Non è richiesta alcuna esperienza precedente. Kotlin Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Star projection e quando usare *»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Kotlin Academy?

Sì. Ogni lezione Kotlin Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Funzioni generiche e vincoli di tipo con where
  2. Varianza dichiarata nel punto di dichiarazione: in e out
  3. Star projection e quando usare *
  4. Type erasure e parametri di tipo reified
← Torna a Kotlin Academy