Middle
Hoe werk je met generieke types in Kotlin?
sobes.tech AI
Antwoord van AI
Generieke types in Kotlin stellen je in staat om klassen, interfaces en functies te maken die werken met gegevens van verschillende types, terwijl ze typeveiligheid tijdens compilatie behouden.
Belangrijke concepten en werkwijzen:
- Declaratie van generieke klassen en interfaces:
class Box<T>(val item: T) // Generieke klasse met typeparameter T interface MyList<E> { // Generieke interface met typeparameter E fun add(element: E) fun get(index: Int): E } - Declaratie van generieke functies:
fun <T> printAnything(value: T) { // Generieke functie met typeparameter T println(value) } - Aanmaken van instanties van generieke types:
val intBox: Box<Int> = Box(123) // Specificatie van een concreet type (Int) val stringBox = Box("hello") // De compiler leidt het type af (String) - Varianten: Hiermee kun je bepalen hoe subtypes werken met generieke types.
- Covariantie (out): Hiermee kun je het type en zijn subtypes gebruiken. Wordt aangegeven met
out. Voorbeeld:List<out Any>kanList<String>bevatten. Gebruikt voor types die waarden produceren (bijvoorbeeld lezen uit collecties).interface Producer<out T> { // out T - covariante parameter fun produce(): T } - Contravariantie (in): Hiermee kun je het type en zijn supertypes gebruiken. Wordt aangegeven met
in. Voorbeeld:Comparator<in String>kan werken metComparator<Any>. Gebruikt voor types die waarden consumeren (bijvoorbeeld schrijven naar collecties).interface Consumer<in T> { // in T - contravariante parameter fun consume(value: T) } - Invariantie: Het type in de generieke parameter moet precies hetzelfde zijn. Dit is het standaardgedrag.
- Covariantie (out): Hiermee kun je het type en zijn subtypes gebruiken. Wordt aangegeven met
- Typebeperkingen (
where): Hiermee kun je het type van de parameter beperken zodat het bepaalde interfaces implementeert of van een bepaalde klasse erft.fun <T : Comparable<T>> max(a: T, b: T): T { // T moet Comparable implementeren return if (a > b) a else b } fun <T> process(item: T) where T : Runnable, T : Comparable<T> { item.run() // ... gebruik van vergelijkbaarheid } - Sterprojectie (
*): Wordt gebruikt wanneer de specifieke argumenten van het type niet belangrijk zijn. Vergelijkbaar met<?>in Java.fun printList(list: List<*>) { // Kan een lijst van elk type accepteren for (item in list) { println(item) } }
Generieke types in Kotlin gebruiken type erasure, zoals in Java. Informatie over specifieke types gaat verloren tijdens runtime. Om met types tijdens runtime te werken, worden reified types gebruikt.
- Reified types (
reified): Alleen beschikbaar voor inline functies. Hiermee kun je de informatie over het type van de parameter tijdens runtime behouden.inline fun <reified T> checkType(value: Any) { // T - reified type if (value is T) { println("Waarde is van type T") } else { println("Waarde is niet van type T") } }