What does `@JvmField` do to how a Kotlin property is exposed to Java, and when would you use it?
answer
- @JvmField = expose raw public field, no accessors
- val -> final field; var -> mutable field
- No custom get/set, not open/override/const/lateinit
- For Java framework field reflection
- Loses encapsulation
basics
~10 s@JvmField makes the property a plain public field for Java instead of generating getter/setter methods. Java can then read or write it directly like obj.x instead of obj.getX().
solid answer
~40 s`@JvmField` tells the compiler to expose the backing field directly with the property's visibility (public field) and to **not generate accessor methods**. Java then accesses it as a raw field: `obj.x` / `obj.x = 5`. It is useful for interop with Java libraries/frameworks that reflect over or expect public fields (e.g. some serialization or test annotations), or to shave the accessor overhead in hot paths. Restrictions: the property must have a backing field, must not be `open`, `override`, `const`, `lateinit`, or have custom getters/setters, and cannot be inside an interface. A `val` annotated with `@JvmField` becomes a `final` public field. Visibility of the field matches the property's Kotlin visibility.
code
kotlin · 5 linesclass Holder {
@JvmField var value: Int = 0 // Java: holder.value = 7;
}
// Without @JvmField, Java would write: holder.setValue(7);go deeper
Knows @JvmField makes Java see a public field instead of getX/setX.
Lists the main restrictions (no custom accessors, not open/const/lateinit) and val->final vs var->mutable.
Weighs the encapsulation/binary-compatibility cost against concrete interop needs and recommends accessors by default.
Sets a policy on when field exposure is acceptable across the codebase and how it interacts with reflection-based frameworks and ABI stability.
## The problem `@JvmField` solves By default a Kotlin property hides its backing field behind accessor methods (`getX()`/`setX()`). Some Java code — frameworks doing field reflection, JUnit `@Rule` fields, certain serializers, or performance-critical code — wants or needs a **plain public field**. `@JvmField` provides exactly that. ## What it does Annotating a property with `@JvmField`: - **Exposes the backing field** with the property's visibility (a `public` Kotlin property -> `public` Java field). - **Suppresses the getter and setter** entirely — there are no `getX()`/`setX()` methods. A `val` -> a `final` field; a `var` -> a non-final, mutable field. ```kotlin class Config { @JvmField var retries: Int = 3 @JvmField val name: String = "default" } ``` From Java: ```java Config c = new Config(); c.retries = 5; // direct field write int r = c.retries; // direct field read String n = c.name; // final field // c.getRetries() does NOT exist ``` ## Restrictions (the compiler enforces these) `@JvmField` is rejected if the property: - has a **custom getter or setter** (there must be a real backing field to expose); - is `open`, `override`, or `const` (`const` already has its own representation); - is `lateinit` (lateinit already exposes a field with a synthetic guard — see related questions); - is declared in an **interface**; - is a **delegated** property (`by`). ## When to use it - Interop with Java frameworks that read/write public fields via reflection. - Java APIs whose contract is "set this field directly." - Micro-optimizing very hot paths to avoid an accessor call (rarely meaningful since the JIT inlines accessors). ## Trade-off You lose the encapsulation benefit: once it is a public field you cannot later add validation in a setter without breaking the Java binary contract. Prefer accessors unless interop forces a field.
- Can you put @JvmField on a property with a custom getter?No. The compiler rejects it because there must be a plain backing field to expose, and a custom getter implies non-trivial accessor logic.
- What does @JvmField do to a `val`?It exposes a `final` public field, so Java can read but not reassign it.
saying these in an interview costs you the question
- Saying it keeps the getter/setter and just also adds a field
- Claiming it works on lateinit or const properties
- Thinking it can be used on a property with a custom accessor
- Not mentioning the loss of encapsulation