Junior
Quali tipi di generici conosci?
sobes.tech AI
Risposta dell'AI
Invariante, covariante e contravariante.
- Invariante: Il tipo
List<A>non è un sottotipo diList<B>e viceversa, anche seAè un sottotipo diB. Il tipo rimane esattamente. - Covariante (out): Permette di usare sottotipi.
List<A>è un sottotipo diList<B>seAè un sottotipo diB. 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 diList<A>seAè un sottotipo diB. 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 | Sì | Sì |
| Covariante | Uso di sottotipi (produttore - "out") | out |
? extends T |
Sì | No |
| Contravariante | Uso di supertipi (consumatore - "in") | in |
? super T |
No | Sì |