skip to content

Beyond plain functions, how do Kotlin interface property accessors with default bodies and methods marked @JvmStatic in interfaces interact with the DefaultImpls / -Xjvm-default mechanism?

level: seniorimportance: nice to knowfreq 18%

answer

  1. Default getters compile like default methods
  2. Legacy: getX body in DefaultImpls, abstract on JVM
  3. all: real default getter, Java inherits
  4. One flag governs functions + accessors
  5. @JvmStatic/companion is a separate concern

basics

~20 s

Interface properties with default getters follow the same rule as default methods: in legacy mode the getter body sits in the helper class; with -Xjvm-default=all it becomes a real default getter Java can inherit. The same flag governs all default members.

solid answer

~40 s

A Kotlin interface property cannot have a backing field, but it can supply a **default getter** (and setter for `var`). These accessors are just methods, so they compile exactly like default functions: in legacy mode the getter/setter body lands in `Iface$DefaultImpls` (`getX($this)`), and the JVM interface accessor stays abstract; under `-Xjvm-default=all` they become real JVM `default` accessor methods inheritable by Java. The `-Xjvm-default` mode therefore governs **all** default members uniformly — functions and property accessors alike. Note `@JvmStatic` is not applicable to ordinary interface members the way it is to companion-object members; static members on interfaces live in the companion, and their JVM placement is a separate concern from DefaultImpls.

code

kotlin · 8 lines
kotlin
interface Config {
    val timeoutMs: Int
        get() = 5000   // legacy: Config$DefaultImpls.getTimeoutMs(this); all: real default getter

    companion object {
        @JvmStatic fun defaults(): Config = TODO()  // static interop, no DefaultImpls
    }
}

go deeper

for a junior

May not realize property getters are compiled like methods at all.

for a middle

Knows default getters exist and have no backing field, but may miss the DefaultImpls parallel.

for a senior

Explains that the same -Xjvm-default strategy applies to accessors and separates @JvmStatic/companion concerns.

for a principal

Reasons about the full interface ABI surface (accessors, companion statics, defaults) when designing Java-friendly Kotlin APIs.

## Default property accessors are methods Kotlin interface properties have **no backing field**, but you can provide a computed default: ```kotlin interface Config { val timeoutMs: Int get() = 5000 // default getter body } ``` The getter `getTimeoutMs()` is compiled with the *same* strategy as a default function: - **Legacy mode**: `getTimeoutMs()` is abstract on the JVM; the body lives in `Config$DefaultImpls.getTimeoutMs(Config $this)`. Java implementors must override `getTimeoutMs()`. - **`-Xjvm-default=all`**: a real JVM `default` getter is emitted; Java inherits it. For a `var` with a default setter, the same applies to `setX`. ## Why this matters for interop A Java class implementing `Config` in legacy mode is forced to implement the getter even though Kotlin code 'sees' a default. Switching the module to `all` removes that friction. So the single `-Xjvm-default` knob covers functions **and** property accessors consistently. ## Static-ish members on interfaces Kotlin places interface 'static' members in a **companion object** of the interface, not directly on it. To expose a companion function as a true JVM `static` on the interface, you use `@JvmStatic` **on the companion member** — this is orthogonal to default-method emission. There is no `DefaultImpls` involvement for companion statics; they get their own placement (a `Companion` nested class, optionally with a static bridge from `@JvmStatic`). ```kotlin interface Codec { companion object { @JvmStatic fun create(): Codec = TODO() // static interop, unrelated to DefaultImpls } } ``` ## Edge cases - A default getter that references another member calls it through `$this` in legacy mode. - Properties with **only** an abstract declaration (no `get()`) generate no DefaultImpls entry — there is no body to host. - Constant-like `const val` is not allowed on interfaces; use a companion `const val` instead, again unrelated to DefaultImpls. ## Keywords default getter/setter, no backing field, `DefaultImpls`, `-Xjvm-default=all`, `@JvmStatic`, companion object.

  • Can an interface property have a backing field to store state for the default getter?
    No. Interface properties have no backing field; a default getter must compute its value or delegate to other (possibly abstract) members.
  • Does @JvmStatic on a companion member change DefaultImpls generation?
    No. @JvmStatic affects how the companion member is exposed as a JVM static; it is unrelated to default-method/DefaultImpls handling.

saying these in an interview costs you the question

  • Claiming interface properties can have backing fields
  • Thinking accessors use a different mechanism than functions
  • Believing @JvmStatic controls DefaultImpls
  • Saying default getters always become real JVM default methods regardless of flag
  • Confusing companion statics with DefaultImpls statics

context