W Kotlinie wprowadzono koncepcję klas inline/value (obecnie nazywanych klasami wartości), aby zminimalizować overhead czasu wykonania związany z używaniem opakowań dla typów prymitywnych i małych struktur. Pomysł został zaczerpnięty z innych języków (np. struktury C#), w których taka optymalizacja jest użyteczna do zwiększenia wydajności bez utraty typizacji.
Tworzenie klas opakowujących (np. dla typów-encji lub identyfikatorów) bez optymalizacji prowadzi do powstawania dodatkowego obiektu w pamięci, co wpływa na wydajność, GC i może prowadzić do kosztów związanych z Boxing/Unboxing. Często pojawia się potrzeba posiadania ścisłej typizacji (np. UserId zamiast Int), ale bez rzeczywistego tworzenia obiektów.
Klasa wartości jest deklarowana z modyfikatorem value. W większości sytuacji JVM nie tworzy dodatkowego obiektu — klasa wartości jest zastępowana swoim polem bezpośrednio (inlining). Daje to bezpieczeństwo typów i wydajność zbliżoną do „po prostu Int”.
Przykład kodu:
@JvmInline value class UserId(val value: Int) fun showId(id: UserId) = println(id.value) val id = UserId(15) showId(id) // Bez tworzenia osobnego obiektu UserId
Kluczowe cechy:
Czy klasy wartości mogą mieć kilka właściwości?
Nie, klasa wartości może zawierać tylko jedną właściwość.
// Błąd: // value class Money(val amount: Int, val currency: String)
Czy można stworzyć klasę wartości z właściwością nullable?
Pole value w klasie wartości nie może być nullable — tylko typy nie-nullable.
// Błąd: // value class Name(val value: String?)
Czy można używać dziedziczenia z klasami wartości?
Klasa wartości nie wspiera dziedziczenia i nie może być abstrakcyjna ani sealed.
// Błąd: // value class NewId(val value: Int): BaseId()
Programista stworzył klasę wartości dla encji z dwiema właściwościami (np. para Int i String), otrzymał błąd kompilacji.
Zalety:
Programista używa klasy wartości dla typu identyfikatora z jednym polem (np. UserId), co działa szybko i bezpiecznie.
Zalety: