skip to content

Property & Field Exposure

A Kotlin property emits a private field plus accessors, with is-prefixed getters for Boolean, while const and @JvmField skip the accessors entirely. Knowing this mapping is essential when a framework reflects over your fields.

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

questions

5

When you declare `var count: Int` in a Kotlin class, what does Java code see when it uses that class?

level: juniorimportance: must knowfreq 70%

answer

  1. var = private field + getter + setter
  2. val = getter only, no setter
  3. Java calls getX()/setX(), not the field
  4. JavaBeans naming
  5. Boolean -> isX()

basics

~10 s

Java does not see a public field. It sees a private hidden field plus two methods: getCount() to read it and setCount() to change it. Java must call those methods.

solid answer

~30 s

A Kotlin `var` compiles to a private backing field plus a public getter and setter. Java cannot touch the field directly; it calls `getCount()` and `setCount(int)`. A `val` produces only a getter (no setter, since it is read-only). The accessor names follow the JavaBeans convention: a property `foo` becomes `getFoo()`/`setFoo()`. For a `Boolean` property named `enabled`, the getter is `isEnabled()` rather than `getEnabled()`. So from Java the property looks like an ordinary JavaBean property accessed through methods, not a raw field.

code

kotlin · 4 lines
kotlin
class Counter {
    var count: Int = 0   // -> private int count; public int getCount(); public void setCount(int)
    val name: String = "x" // -> private final String name; public String getName()
}

go deeper

for a junior

Knows var produces getter+setter and val produces only a getter, and that the field is private.

for a middle

Adds the JavaBeans naming convention and that accessors exist precisely to keep the field private.

for a senior

Explains the binary-compatibility motivation: accessors let you add logic later without breaking Java callers.

for a principal

Frames the field/accessor split as part of the public ABI surface to govern across a multi-module Java/Kotlin codebase.

## What a Kotlin property is In Kotlin a *property* is not a field — it is a name with an optional **backing field** and a pair of **accessors** (a getter, and for a `var`, a setter). When Kotlin compiles to JVM bytecode it must express this using Java constructs: a real field plus methods. ## What gets generated for `var count: Int` - A **private backing field** named `count` (referenced inside Kotlin as `field`). Private means Java cannot read or write it directly. - A **public getter** `int getCount()`. - A **public setter** `void setCount(int)`. For a read-only `val count: Int`, only the getter is generated — there is no setter, matching the fact that a `val` cannot be reassigned. ## Naming rules (JavaBeans convention) - Property `name` -> `getName()` / `setName()`. - A property whose **type is `Boolean`** and whose **name already starts with `is`** (e.g. `isActive`) keeps that name: the getter is `isActive()` and the setter is `setActive(...)` (the `is` is dropped on the setter). A boolean property *not* starting with `is`, e.g. `enabled`, still gets `isEnabled()` as the getter under Kotlin's convention. ## Why methods, not a public field Going through accessors lets Kotlin add custom get/set logic, validation, or lazy computation later **without breaking the binary API** seen by Java. This is the same reason JavaBeans use getters/setters. ```kotlin class Counter { var count: Int = 0 // private field + getCount()/setCount() val label: String = "hi" // private field + getLabel() only } ``` From Java: ```java Counter c = new Counter(); c.setCount(5); int n = c.getCount(); String s = c.getLabel(); // c.count is NOT accessible — it is private ``` ## Key takeaway A `var` -> private field + getter + setter; a `val` -> private field + getter only; Java always goes through the accessor methods.

  • What changes if you use `val` instead of `var`?
    Only a getter is generated; there is no setter, so Java can read but not write the property.
  • Can Java read the backing field directly?
    No. The backing field is private by default, so Java must use the generated accessor methods.

The property is like a vending machine: you press buttons (getter/setter) and never reach inside to grab the stock (the private field) directly.

saying these in an interview costs you the question

  • Saying Java sees a public field named count
  • Claiming a val also gets a setter
  • Thinking the accessors are named count()/count(value) instead of getCount()/setCount()
  • Believing Kotlin properties are just public fields with no methods

context

open as a page

How does a top-level/companion `const val` differ from a regular `val` when accessed from Java?

level: middleimportance: should knowfreq 50%

basics

~20 s

A const val becomes a real compile-time constant field that Java reads directly by name. A regular val in a companion object is reached through a getter and the Companion reference, so Java needs more ceremony.

open as a page

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

level: middleimportance: should knowfreq 55%

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().

open as a page

How is a `lateinit var` exposed to Java, and what is the 'synthetic guard' associated with it?

level: seniorimportance: should knowfreq 35%

basics

~10 s

A lateinit var becomes a real public field that Java can read and write directly. Kotlin still inserts a hidden check so that reading it before assignment throws an exception instead of returning null.

open as a page

A Kotlin class has `val isActive: Boolean` and `val enabled: Boolean`. What getter names does Java see, and what subtle interop pitfall can the `is` prefix cause?

level: seniorimportance: nice to knowfreq 25%

basics

~20 s

For a boolean property whose name already starts with is, Kotlin keeps that name as the getter (isActive()). For other boolean properties it adds is, so enabled gets isEnabled(). Mismatched expectations can break frameworks that look for getEnabled().

open as a page