In Kotlin ermöglichen inline classes (seit Kotlin 1.5 — der Begriff "value class"), Typen mit minimalen Overhead zu umhüllen. Bei der Kompilierung werden solche Klassen im Hintergrund durch ihren inneren Wert (value) ersetzt, um die Kosten für die Erstellung von Objekten zu vermeiden.
Einschränkungen und Besonderheiten:
=== funktioniert nicht wie gewohnt).Beispiel:
@JvmInline value class UserId(val value: String) fun getUser(id: UserId) { println("Lade Benutzer mit ID: ${id.value}") } val id = UserId("XYZ") getUser(id) // Funktioniert im Hintergrund einfach mit String!
Wann verwenden:
Kann man eine value class erben oder sie in einer Hierarchie von Interfaces/abstrakten Klassen verwenden?
Antwort: Nein, eine value class kann keine anderen Klassen (außer Interfaces) erben, kann nicht für die Vererbung geöffnet werden, erlaubt keinen Init-Block und keine anderen nicht-statischen Felder. Die einzige verfügbare Option besteht darin, Interfaces zu implementieren.
Beispiel:
interface Validatable { fun isValid(): Boolean } @JvmInline value class Email(val raw: String) : Validatable { override fun isValid() = raw.contains("@") }
Geschichte
Eine Android-Anwendung erhöhte die Startzeit drastisch, nachdem value classes als Parameter für Parcelable hinzugefügt wurden: Es stellte sich heraus, dass ein inkorrektes @Parcelize mit value class zu Boxing/Unboxing in jeder Phase der Serialisierung führte und somit die Vorteile von inline zunichte machte.
Geschichte
Ein Mikrodienst begann aktiv, value classes für UserId und ProductId zur Gewährleistung der Typensicherheit zu verwenden, aber an vielen Stellen erforderten generische Funktionen Reflektion, die nicht mit der "Wrapper"-Klasse funktionierte. Unit-Tests fielen unerwartet aus, es traten ClassCastException auf.
Geschichte
Der von Java migrierte Code begann, interne Domänenklassen durch value classes zur Optimierung zu ersetzen, aber die Verwendung als nullable-Felder führte zu unerwarteten Null Pointer Exceptions, da eine value class nur dann null sein kann, wenn der äußere Wert ebenfalls null ist, was alte Invarianten brach.