A Java class exposes a public instance field `public int count;` with no getter/setter. How do you read and write it from Kotlin, and how does that differ from a JavaBean property?
answer
- Public Java field → obj.count read, obj.count = x write
- final field → read-only (val-like), assignment is a compile error
- Field access is direct getfield/putfield, not a method call
- Getter+field name clash → getter property wins
- Different from JavaBean getCount()/setCount() synthesis
basics
~10 sYou access a public Java field directly by name: obj.count to read and obj.count = 5 to write. It looks just like a Kotlin property even though Java has no getter or setter.
solid answer
~40 sKotlin exposes a public Java instance field as if it were a property: read with `obj.count`, assign with `obj.count = 5` (assignment works only if the field is non-`final`). This is distinct from the JavaBean rule, where Kotlin synthesizes a property from `getCount()`/`setCount()` accessor methods. With a raw field there are no accessors at all — Kotlin reads/writes the field directly via the `getfield`/`putfield` bytecode. A `final` field becomes effectively read-only (val-like) in Kotlin; trying to assign it is a compile error. Edge case: if a public field's name collides with a Java getter (e.g. field `count` plus method `getCount()`), Kotlin prefers the property synthesized from the getter, and the raw field is reachable via the `@JvmField`-style direct name only when no accessor shadows it.
code
kotlin · 6 lines// Java: class Point { public int x; public final int origin = 0; }
fun move(p: Point) {
val current = p.x // direct field read
p.x = current + 1 // direct field write (x is non-final)
// p.origin = 5 // COMPILE ERROR: origin is final -> read-only
}go deeper
Knows you read/write a public Java field as obj.count and obj.count = 5.
Distinguishes raw field access from getter-synthesized properties and knows final → read-only.
Explains the bytecode-level difference (getfield/putfield vs invoke), name-collision resolution, and side-effect implications.
Considers API design: when to expose Kotlin properties as @JvmField vs accessors for Java consumers, and the ABI/encapsulation trade-offs.
## Two different mechanisms Kotlin presents Java members as Kotlin **properties** in two unrelated ways. Don't conflate them: 1. **JavaBean accessors → synthesized property.** If Java has `getCount()`/`setCount(int)` (or `isReady()` for booleans), Kotlin *synthesizes* a property named `count`/`ready`. Reading `obj.count` actually calls `getCount()`. 2. **Public field → direct field access.** If Java declares `public int count;` with **no** accessors, Kotlin lets you write `obj.count` and `obj.count = 5`, and these compile to direct field reads/writes (`getfield`/`putfield`), **not** method calls. ## Reading and writing a public field ```kotlin val p = SomeJavaClass() val c = p.count // direct field read (getfield) p.count = 5 // direct field write (putfield) — only if non-final ``` ## final fields are read-only A `public final int count;` is exposed as a **read-only** property in Kotlin. Assigning to it is a compile-time error, analogous to assigning to a `val`: ```kotlin p.count = 5 // error if the Java field is final ``` ## Field vs property: why it matters The difference is observable: - A synthesized property may run logic inside `getCount()` (validation, lazy init, side effects). - A raw field access is a plain memory read/write with no logic. So `obj.count` is *not always* a method call — it depends on whether Java exposed a field or a getter. ## Name collisions If Java has both `public int count;` and `int getCount()`, Kotlin resolves `obj.count` to the **getter-based property** (accessors win). The underlying field is then effectively shadowed for property-style access. ## Relation to statics The same direct-access model applies to static fields: `System.out` is a public static field read directly, while `Integer.MAX_VALUE` is a `public static final` constant read the same way. ## Key keywords/APIs Direct field access (`getfield`/`putfield`), JavaBean getter/setter synthesis, `final` → read-only property, `@JvmField` (the Kotlin-side mechanism to expose a Kotlin property *as* a plain field to Java — the reverse direction).
- Is reading a public Java field the same as calling a getter under the hood?No. A public field compiles to a direct getfield read; a synthesized property from getCount() compiles to a method call. The distinction matters when the getter has side effects.
- What if the Java field is final?Kotlin treats it as read-only (like a val); assigning to it is a compile-time error.
saying these in an interview costs you the question
- Claiming obj.count always calls a getter method
- Saying you can assign to a final Java field from Kotlin
- Thinking you must use reflection to read a public field
- Confusing JavaBean synthesis with raw field access