TL; DR: Wofür ist das reifiedgut ?
fun <T> myGenericFun(c: Class<T>)
Im Hauptteil einer generischen Funktion wie myGenericFunkönnen Sie nicht auf den Typ zugreifen, Tda er nur zur Kompilierungszeit verfügbar ist, aber zur Laufzeit gelöscht wird. Wenn Sie den generischen Typ als normale Klasse im Funktionskörper verwenden möchten, müssen Sie die Klasse daher explizit als Parameter übergeben, wie in gezeigt myGenericFun.
Wenn Sie jedoch eine inlineFunktion mit einem Reified erstellen T, kann auf den Typ von Tauch zur Laufzeit zugegriffen werden, sodass Sie die Funktion nicht Class<T>zusätzlich übergeben müssen. Sie können damit arbeiten, Tals wäre es eine normale Klasse, z. B. möchten Sie möglicherweise überprüfen, ob eine Variable eine Instanz von ist T , was Sie dann einfach tun können:myVar is T .
Eine solche inlineFunktion mit reifiedTyp Tsieht wie folgt aus:
inline fun <reified T> myGenericFun()
Wie reified funktioniert
Sie können nur reifiedin Kombination mit einer inlineFunktion verwenden . Durch eine solche Funktion kopiert der Compiler den Bytecode der Funktion an jede Stelle, an der die Funktion verwendet wird (die Funktion wird "inline"). Wenn Sie eine Inline-Funktion mit reifiziertem Typ aufrufen, kennt der Compiler den tatsächlichen Typ, der als Typargument verwendet wird, und ändert den generierten Bytecode, um die entsprechende Klasse direkt zu verwenden. Daher werden Aufrufe wie myVar is Twerden myVar is String(wenn das Typargument wäre String) im Bytecode und zur Laufzeit.
Beispiel
Schauen wir uns ein Beispiel an, das zeigt, wie hilfreich es sein reifiedkann. Wir möchten eine Erweiterungsfunktion für Stringaufgerufene erstellen toKotlinObject, die versucht, eine JSON-Zeichenfolge in ein einfaches Kotlin-Objekt mit einem Typ zu konvertieren, der durch den generischen Typ der Funktion angegeben wird T. Wir können com.fasterxml.jackson.module.kotlindies verwenden und der erste Ansatz ist der folgende:
a) Erster Ansatz ohne reifizierten Typ
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
Die readValueMethode verwendet einen Typ, den sie analysieren JsonObjectsoll. Wenn wir versuchen, den ClassParameter type zu erhalten T, beschwert sich der Compiler: "'T' kann nicht als reifizierter Typparameter verwendet werden. Verwenden Sie stattdessen eine Klasse."
b) Problemumgehung mit expliziten ClassParametern
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
Als Problemumgehung kann das Classof Tzu einem Methodenparameter gemacht werden, der dann als Argument für verwendet wird readValue. Dies funktioniert und ist ein allgemeines Muster im generischen Java-Code. Es kann wie folgt aufgerufen werden:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c) Der Kotlin-Weg: reified
Die Verwendung einer inlineFunktion mit reifiedTypparameter Termöglicht es, die Funktion anders zu implementieren:
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
Es gibt keine Notwendigkeit , das nehmen Classvon Tzusätzlich, Tkann verwendet werden , als ob es sich um eine normale Klasse. Für den Client sieht der Code folgendermaßen aus:
json.toKotlinObject<MyJsonType>()
Wichtiger Hinweis: Arbeiten mit Java
Eine Inline-Funktion mit reifiedTyp kann nicht über Java- Code aufgerufen werden.