skip to content

@JvmField

@JvmField exposes a property as a plain public field with no accessors, which some frameworks and Java callers expect. The rules around when it is allowed — no custom accessors, no open, no private — are the follow-up.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What does the @JvmField annotation do, and why would you use it when calling Kotlin code from Java?

level: juniorimportance: must knowfreq 55%

answer

  1. Property = backing field + getter/setter by default
  2. @JvmField drops accessors, exposes the field
  3. Java writes obj.x instead of obj.getX()
  4. No const/open/override/private/custom-accessor
  5. 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 s

By 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 lines
kotlin
class 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);          // accessor

go deeper

for a junior

Knows it exposes a property as a direct public field for Java instead of getter/setter.

for a middle

Lists the constraints (no custom accessor, not open/const/private) and a real interop use case.

for a senior

Discusses tradeoffs vs encapsulation and that future accessor logic becomes impossible without breaking the API.

for a principal

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

context

open as a page

How do you use @JvmField on companion object properties, and what does it fix for Java callers?

level: middleimportance: should knowfreq 40%

basics

~20 s

A companion property is normally reached from Java via the Companion holder and a getter. @JvmField on it moves the field up to the outer class as a static field, so Java writes Outer.NAME directly.

open as a page

Compare @JvmField with const for exposing values to Java. When does each apply, and what does Java see?

level: middleimportance: should knowfreq 45%

basics

~20 s

const makes a compile-time constant Java sees as a static final field. @JvmField exposes a normal mutable-or-not field with no accessors. You cannot combine them — const already produces a public static final field for Java.

open as a page

Which property declarations cannot be marked @JvmField, and why does each restriction exist?

level: seniorimportance: should knowfreq 35%

basics

~20 s

@JvmField needs a real backing field with default accessors. It's rejected on properties that are private, open/override, const, delegated, have custom get/set, are computed, or live in an interface — because there's no plain public field to expose.

open as a page

You maintain a Kotlin library consumed heavily from Java. What are the design tradeoffs of exposing data with @JvmField instead of normal properties?

level: seniorimportance: nice to knowfreq 25%

basics

~10 s

@JvmField gives Java a clean direct field and slightly cheaper access, but you lose encapsulation: you can't later add validation, laziness, or override behavior without breaking the public API for already-compiled Java callers.

open as a page