Kotlin Academy · Oppitunti

Tyyppien häviäminen ja reified-tyyppiparametrit

Käyttäkää reified-määrettä inline-funktioiden kanssa tyyppitietojen käyttämiseen ajon aikana.

Oppitunti 4/414 vaihetta

Tyyppien häviäminen ja reified-tyyppiparametrit on ilmainen Kotlin Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Kotlin Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Kotlin Academy-kurssilla on yhteensä 4 oppituntia.

Mikä on tyyppien häivytys?

Ajonaikana JVM häivyttää geneeristen tyyppien argumentit. List<String> ja List<Int> ovat molemmat vain List. Tämä rajoittaa geneerisiin tyyppeihin kohdistuvia tyyppioperaatioita ajonaikana.

fun main() {
    val strings: List<String> = listOf("a", "b")
    val ints: List<Int> = listOf(1, 2)
    println(strings.javaClass == ints.javaClass) // true: both ArrayList
    println(strings is List<*>)  // OK with star
    // println(strings is List<String>) // warning: unchecked cast
}

Ongelma: häivytettyjä tyyppejä ei voi tarkistaa

is-operaattoria ei voi käyttää tietyn geneerisen tyyppiargumentin kanssa, koska tyyppitieto on kadonnut ajonaikana.

fun checkType(obj: Any) {
    // This works:
    if (obj is List<*>) println("It's a list of something")
    // This doesn't compile cleanly:
    // if (obj is List<String>) println("It's a list of strings") // unchecked
}
fun main() {
    checkType(listOf("hello"))
    checkType(42)
}

inline-funktioiden kertaus

inline kopioi funktion rungon kutsukohtaan käännösaikana. Tämä mahdollistaa reified-määreen — myös tyyppiargumentti korvataan kutsukohdassa.

inline fun <T> myRun(block: () -> T): T = block()
fun main() {
    val result = myRun { 42 }
    println(result) // 42
    // The compiler inlines the lambda body — no object allocation
}

reified: T:n käyttäminen ajonaikana

Kun yhdistät inline- ja reified-määreet, tyyppiargumentti säilyy kutsukohdassa, joten T:hen voi käyttää operaatioita is, as ja ::class.

inline fun <reified T> isInstance(value: Any): Boolean = value is T
fun main() {
    println(isInstance<String>("hello"))  // true
    println(isInstance<Int>("hello"))     // false
    println(isInstance<List<*>>(listOf())) // true
}

T:n KClass-arvon hakeminen

reified T-määreen avulla voit hakea arvon T::class ajonaikana — geneerisissä funktioissa tämä ei yleensä ole mahdollista.

inline fun <reified T> classNameOf(): String = T::class.simpleName ?: "Unknown"
fun main() {
    println(classNameOf<String>())   // String
    println(classNameOf<Int>())      // Int
    println(classNameOf<List<*>>())  // List
}

Turvallinen muunnos reified-määreellä

Käytä reified-määrettä tyyppiturvallisen muunnosapuohjelman kirjoittamiseen niin, että se palauttaa null-arvon poikkeuksen heittämisen sijaan.

inline fun <reified T> Any?.safeCast(): T? = this as? T
fun main() {
    val obj: Any = "Hello"
    val s: String? = obj.safeCast<String>()
    val i: Int? = obj.safeCast<Int>()
    println(s) // Hello
    println(i) // null
}

JSON-jäsennys reified-määreellä

Gsonin ja kotlinx.serializationin kaltaiset kirjastot käyttävät reified-määrettä kohdetyypin päättelemiseen kutsukohdassa ilman, että Class-olioita tarvitsee välittää erikseen.

import com.google.gson.Gson
// Simulated without real Gson:
inline fun <reified T> parseJson(json: String): T {
    return Gson().fromJson(json, T::class.java)
}
// Usage:
// val user: User = parseJson<User>("""{"name":"Alice"}""")

reified ja filterIsInstance

Standardikirjaston filterIsInstance<T>() käyttää reified-määrettä suodattaakseen listasta tietyn tyyppiset alkiot ilman manuaalisia tyyppimuunnoksia.

fun main() {
    val mixed: List<Any> = listOf(1, "hello", 2.5, "world", true)
    val strings = mixed.filterIsInstance<String>()
    val ints = mixed.filterIsInstance<Int>()
    println(strings) // [hello, world]
    println(ints)    // [1]
}

reified-määrettä ei voi käyttää ei-inline-funktioissa

reified toimii vain inline-funktioiden kanssa. Sen käyttäminen ilman inline-määrettä aiheuttaa käännösvirheen.

// Error:
// fun <reified T> broken(): String = T::class.simpleName ?: "?"

// Must be inline:
inline fun <reified T> correct(): String = T::class.simpleName ?: "?"
fun main() {
    println(correct<Double>()) // Double
}

reified ja reflektio

Yhdistä reified-määre reflektioon, jotta voit tarkastella tyypin ominaisuuksia tai annotaatioita dynaamisesti ilman ylimääräisiä Class-parametreja.

inline fun <reified T : Any> properties(): List<String> =
    T::class.members.map { it.name }
data class Point(val x: Int, val y: Int)
fun main() {
    println(properties<Point>()) // [x, y, component1, component2, copy, equals, hashCode, toString]
}

Käytännössä: tyyppiturvallinen palvelupaikannin

Käytä reified-määrettä palvelupaikantimen rakentamiseen: se yhdistää KClass-arvot instansseihin ja mahdollistaa kevyen riippuvuuksien injektoinnin ilman annotaatioprosessoreita.

val registry = mutableMapOf<kotlin.reflect.KClass<*>, Any>()
inline fun <reified T : Any> register(instance: T) { registry[T::class] = instance }
@Suppress("UNCHECKED_CAST")
inline fun <reified T : Any> resolve(): T = registry[T::class] as T
class Logger { fun log(msg: String) = println("[LOG] $msg") }
fun main() {
    register(Logger())
    resolve<Logger>().log("Service located!")
}

reified-määreen rajoitukset

reified-tyyppiparametreja ei voi käyttää ei-inline-konteksteissa, tyyppiä ei voi tallentaa myöhempää käyttöä varten eikä sitä voi välittää ei-inline-funktioille, jotka tarvitsevat tyypin ajonaikana.

inline fun <reified T> foo() {
    val clazz = T::class // OK here
    // bar(clazz)        // must pass clazz explicitly to non-inline funs
    println(clazz.simpleName)
}
fun bar(clazz: kotlin.reflect.KClass<*>) = println(clazz.simpleName)
fun main() { foo<String>() }

Pikatarkistus

Mitä tarvitaan, jotta tyyppiparametri voi olla reified?

Kertaus

Tyyppien häivytys poistaa geneeristen tyyppien tiedot ajonaikana. inline-funktioiden reified-määre säilyttää tyyppiargumentin kutsukohdassa ja mahdollistaa operaattorit is, as, ::class sekä T:hen kohdistuvan reflektion — ilman manuaalisesti välitettäviä Class-olioita.

Aloita maksutta

Opi Kotlin tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
51
Oppitunnit
203

Usein kysytyt kysymykset

Onko oppitunti ”Tyyppien häviäminen ja reified-tyyppiparametrit” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Kotlin Academy-oppimispolun 3 oppituntia, myös oppitunnin “Tyyppien häviäminen ja reified-tyyppiparametrit”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Kotlin Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Tyyppien häviäminen ja reified-tyyppiparametrit”?

Käyttäkää reified-määrettä inline-funktioiden kanssa tyyppitietojen käyttämiseen ajon aikana. Harjoittelet Kotlin Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Kotlin Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Kotlin Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”Tyyppien häviäminen ja reified-tyyppiparametrit”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Kotlin Academy-oppitunnilla?

Kyllä. Jokainen Kotlin Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Geneeriset funktiot ja tyyppirajoitteet wherella
  2. Deklaraatiopaikan varianssi: in ja out
  3. Star projection ja *-merkin käyttötarkoitus
  4. Tyyppien häviäminen ja reified-tyyppiparametrit
← Takaisin: Kotlin Academy