Sobes.tech
Junior

Quali tipi di generici conosci?

sobes.tech AI

Risposta dell'AI

Invariante, covariante e contravariante.

  • Invariante: Il tipo List<A> non è un sottotipo di List<B> e viceversa, anche se A è un sottotipo di B. Il tipo rimane esattamente.
  • Covariante (out): Permette di usare sottotipi. List<A> è un sottotipo di List<B> se A è un sottotipo di B. Usato per parametri di output (valori restituiti).
fun foo(list: List<out Number>) {
    // Si può leggere dalla lista (Number, Double, Int, ecc.)
    val number: Number = list[0]
    // Non si può aggiungere alla lista (non si sa che tipo di elementi si aspettano)
    // list.add(1) // Errore di compilazione
}
  • Contravarianti (in): Permette di usare supertipi. List<B> è un sottotipo di List<A> se A è un sottotipo di B. Usato per parametri di input (argomenti).
fun foo(comparable: Comparable<in String>) {
    // Si possono passare argomenti String (o i suoi supertipi)
    val result = comparable.compareTo("hello")
    // Non si possono ottenere risultati di tipo String (non si sa che tipo di risultato)
    // val str: String = comparable.compareTo("world") // Errore di compilazione
}

In Kotlin questi concetti sono implementati con le annotazioni out e in sui parametri di tipo. In Java si usano wildcards (? extends per covarianza e ? super per contravarianza).

Tipo Scopo Parola chiave (Kotlin) Wildcard (Java) Lettura consentita Scrittura consentita
Invariante Corrispondenza esatta del tipo No No
Covariante Uso di sottotipi (produttore - "out") out ? extends T No
Contravariante Uso di supertipi (consumatore - "in") in ? super T No