What is a Kotlin value class, and why must it be annotated with @JvmInline on the JVM?
answer
- value keyword + exactly one val
- @JvmInline required on JVM, else won't compile
- zero-overhead wrapper, no heap allocation
- old name: inline class (pre-1.5)
- kotlin.jvm package
basics
~20 sA value class wraps one value (like a String or Int) in a new type without the cost of a real object. On the JVM you add @JvmInline so Kotlin can store just the wrapped value instead of a wrapper object.
solid answer
~40 sA value class is declared as `value class X(val v: T)` and holds exactly one read-only property in its primary constructor. It gives you a distinct compile-time type (e.g. `UserId` vs `OrderId`) for type safety, while the compiler tries to represent it at runtime as the underlying value with no wrapper allocation. On the JVM the `value` keyword alone is not enough: you must also add `@JvmInline`, because the JVM has no native value-type support, so this annotation tells the Kotlin compiler to use the inline (unboxed) JVM representation. Without `@JvmInline`, `value class` does not compile for a JVM target. The single property must be a `val`, and the class can still have computed properties, functions, and implement interfaces.
code
kotlin · 8 lines@JvmInline
value class Email(val value: String)
fun send(to: Email) { /* ... */ }
val e = Email("[email protected]") // no wrapper object allocated at runtime
send(e)
// send("[email protected]") // compile error: String is not Emailgo deeper
Knows the basic syntax, that it wraps one val, and that @JvmInline is needed on the JVM.
Explains the type-safety vs performance motivation and that without @JvmInline it doesn't compile on JVM.
Connects it to the old inline class history, init-block validation, and when the unboxed representation actually applies.
Frames it as a multiplatform abstraction over absent JVM value types and reasons about API design implications of zero-overhead domain types.
## What a value class is A **value class** is a class whose identity is defined entirely by the single value it wraps. You declare it with the `value` soft keyword and exactly one property in the primary constructor: ```kotlin @JvmInline value class UserId(val raw: String) ``` The goal is a **zero-overhead type wrapper**: at compile time you get a brand-new type (so `UserId` and `OrderId` are not interchangeable, preventing argument mix-ups), but at runtime the compiler tries to use the *underlying* value (`String`) directly, with **no wrapper object allocated** on the heap. ## Why @JvmInline is required `value class` is a multiplatform Kotlin concept. The **JVM has no native notion of value types**, so Kotlin needs to know *how* to represent the class on that platform. The `@JvmInline` annotation tells the compiler: "use the **inline** representation" — i.e. substitute the wrapped value in place of the wrapper wherever possible. - On the JVM, `value class` **without** `@JvmInline` does **not compile**. - The annotation is in package `kotlin.jvm`. - Historically this feature was called `inline class` (the `inline class X(...)` syntax, before Kotlin 1.5). The modern form is `@JvmInline value class`. ## Rules of the single property - Exactly **one** property, declared as `val` in the primary constructor. `var` is not allowed. - The class can have additional members: computed `val`s (backed by the underlying field, not new state), functions, and `init` blocks. - It can implement interfaces but cannot extend a class (it implicitly inherits from `Any`). ```kotlin @JvmInline value class Password(private val value: String) { init { require(value.length >= 8) { "too short" } } fun masked(): String = "*".repeat(value.length) } ``` ## What you gain - **Type safety**: distinct domain types instead of bare `String`/`Int`. - **Performance**: no heap allocation in the common case, so it behaves like the raw value. - **Validation**: the `init` block can enforce invariants once at construction.
- Can a value class hold two properties?No. The primary constructor must have exactly one property. For multiple fields you need a regular or data class.
- Must the single property be val or can it be var?It must be val. Value classes are immutable, so var is disallowed.
Like writing a label on an envelope's contents: the type system sees a labeled, distinct thing, but at runtime you're really just handling the raw contents directly.
saying these in an interview costs you the question
- Saying value class can wrap multiple properties
- Claiming @JvmInline is optional on the JVM
- Confusing value class with data class
- Saying the property can be a var
- Thinking it always allocates a wrapper object like a normal class