Achtergrond van de vraag:
In de JVM ontbreekt informatie over generieke parameters tijdens runtime (type erasure). Kotlin heeft een mechanisme voor gereifiseerde generieke parameters voor inline-functies voorgesteld, zodat toegang tot type-informatie T tijdens uitvoering mogelijk is zonder hacks zoals het doorgeven van Class<T>. Dit is een van de krachtigste middelen van de Kotlin-taal.
Probleem:
Er moet een functie worden geschreven die een bepaalde waarde van type T (generiek) accepteert en afhankelijk van het type parameter verschillende acties onderneemt, zonder expliciet java.lang.Class door te geven en zonder reflectie op Java-niveau. De klassieke type-erasure maakt het onmogelijk om het type T tijdens runtime te achterhalen.
Oplossing:
In Kotlin is het toegestaan om voor inline-functies generieke parameters met de modifier gerefied te declareren, wat het mogelijk maakt om het type T binnen de functie uit te "verzegelen", ermee te werken als met een gewoon type, type-checks uit te voeren en exemplaren te creëren via reflectie.
Voorbeeld code:
inline fun <reified T> isOfType(value: Any): Boolean { return value is T } isOfType<String>(123) // false isOfType<Int>(123) // true
Kernkenmerken:
Kan je gerefied buiten inline-functies gebruiken?
Nee! Alleen inline-functies (en inline-lazy properties) kunnen een gerefied generieke parameter hebben. De reden hiervoor is dat de code op de plaats van de aanroep moet worden ingevoegd, alleen zo kan een specifiek type in plaats van T worden "aangevoerd".
Voorbeeld code:
// Compilatiefout: fun <reified T> errorFun() { } // Correcte versie: inline fun <reified T> okFun() { }
Kan je Class<T> binnen een inline gerefied functie krijgen?
Ja! Dit kan eenvoudig worden gedaan door T::class.java of T::class te schrijven. Dit is uiterst handig voor het schrijven van generieke fabrieken, parsers en het werken met de reflectie-API.
Voorbeeld code:
inline fun <reified T> printType() { println(T::class.java) } printType<String>() // class java.lang.String
Kan je exemplaren van type T via de constructor in een gerefide functie maken?
Deels. Je kunt reflectie gebruiken, maar direct new T() zoals in C++ of C# is niet mogelijk:
inline fun <reified T : Any> makeInstance(): T? { return T::class.constructors.firstOrNull()?.call() }
Maar deze aanpak vereist een constructor zonder parameters voor T.
Een functie met gerefied die een zware reflectie-operatie in de code aanroept:
inline fun <reified T> foo(): T? = T::class.constructors.firstOrNull()?.call()
Voordelen:
Nadelen:
Gebruik van gerefied voor een universele type-check of safeCast:
inline fun <reified T> safeCast(value: Any?): T? = value as? T
Voordelen:
Nadelen: