What does the @JvmField annotation do, and why would you use it when calling Kotlin code from Java?
answer
- Property = backing field + getter/setter by default
- @JvmField drops accessors, exposes the field
- Java writes obj.x instead of obj.getX()
- No const/open/override/private/custom-accessor
- Kotlin still sees it as a normal property
basics
~10 s@JvmField turns a Kotlin property into a plain public field. Java code can then read or write it directly as obj.x instead of calling getX() or setX().
solid answer
~40 sBy default the Kotlin compiler exposes a property to Java through a private backing field plus a getter (and a setter for `var`). Java must call `getX()`/`setX()`. Marking the property `@JvmField` suppresses the accessors and exposes the backing field itself as a public Java field, so Java writes `obj.x` directly. The Kotlin property must have a backing field, must not be `open`, `override`, `const`, `private`, or have custom accessors, and cannot be `lateinit` at the top level only in certain forms — actually `lateinit` is allowed. It is most useful for interop with Java/JNI/serialization libraries that reflect over fields, or to drop accessor overhead. Inside Kotlin you still access it as a normal property.
code
kotlin · 9 linesclass Config {
@JvmField var retries: Int = 3 // exposed as public field `retries`
var timeout: Int = 30 // exposed as getTimeout()/setTimeout()
}
// Java:
// Config c = new Config();
// c.retries = 5; // direct field
// c.setTimeout(60); // accessorgo deeper
Knows it exposes a property as a direct public field for Java instead of getter/setter.
Lists the constraints (no custom accessor, not open/const/private) and a real interop use case.
Discusses tradeoffs vs encapsulation and that future accessor logic becomes impossible without breaking the API.
Frames it as an interop/ABI surface decision and weighs reflection-based framework needs against API evolution and Kotlin-idiomatic design.
## The problem @JvmField solves Kotlin has **properties**, not fields. A Kotlin property like `var name: String` is compiled, by default, into: - a **private backing field** (the actual storage slot), plus - a **public getter** `getName()` and, for `var`, a **public setter** `setName(...)`. The term **backing field** means the hidden variable that stores the property's value; **accessor** means the generated `getX()`/`setX()` method. So from **Java**, you cannot write `obj.name` — you must call `obj.getName()` and `obj.setName(...)`. ## What @JvmField changes Marking the property with `@JvmField` tells the compiler: *do not generate a getter/setter; expose the backing field itself as a public Java field.* Java then accesses it directly: ```kotlin class Point(@JvmField var x: Int, @JvmField var y: Int) ``` ```java // Java Point p = new Point(1, 2); p.x = 10; // direct field write, no setter int sum = p.x + p.y; ``` From **Kotlin** nothing changes — you still write `p.x`, treating it as a property. ## Rules / constraints The property MUST: - have a **backing field** (so not a computed property), - have **default getter and setter** (no custom `get()`/`set()`), - not be `private`, `open`, `override`, or `const`, - not be declared inside an `interface`, - not be a delegated property (`by`). `lateinit var` **can** be `@JvmField`. A `companion object` property can be `@JvmField` (covered separately) to avoid the `Companion` indirection. ## When to use it - **Interop performance / ergonomics**: Java/JNI code or frameworks (some serializers, ORMs, game/Android libraries) that reflect over or directly touch public fields. - **Plain data carriers** exposed to Java where accessors add no value. Otherwise prefer normal properties — they keep encapsulation and let you later add logic in an accessor without breaking the API.
- Does @JvmField change how Kotlin code accesses the property?No. Kotlin always uses property syntax `obj.x`; @JvmField only affects the generated JVM bytecode/Java-facing shape.
- Can you put @JvmField on a computed property like `val area get() = w * h`?No — it has no backing field and a custom getter, so the compiler rejects @JvmField.
Default property = a vending machine (you push buttons/accessors); @JvmField = removing the glass so Java grabs the item directly.
saying these in an interview costs you the question
- Saying Kotlin properties are plain fields by default (they generate accessors)
- Claiming @JvmField works on properties with custom get()/set()
- Thinking it changes Kotlin-side access syntax
- Confusing @JvmField with @JvmStatic
- Saying it can be applied to `const`/`open` properties