skip to content

What does `@JvmField` do to how a Kotlin property is exposed to Java, and when would you use it?

level: middleimportance: should knowfreq 55%

answer

  1. @JvmField = expose raw public field, no accessors
  2. val -> final field; var -> mutable field
  3. No custom get/set, not open/override/const/lateinit
  4. For Java framework field reflection
  5. 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 lines
kotlin
class Holder {
    @JvmField var value: Int = 0   // Java: holder.value = 7;
}

// Without @JvmField, Java would write: holder.setValue(7);

go deeper

for a junior

Knows @JvmField makes Java see a public field instead of getX/setX.

for a middle

Lists the main restrictions (no custom accessors, not open/const/lateinit) and val->final vs var->mutable.

for a senior

Weighs the encapsulation/binary-compatibility cost against concrete interop needs and recommends accessors by default.

for a principal

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

context