In fact, the only necessary part is the getter method.
If you define a simple property, e.g.:
val myField = 1
…then the compiler will generate a backing field which is private
(unless overridden by an annotation), and a getter method of the relevant visibility (in this case public
). If it were a var
, it would have a setter method too.
But you can define your own accessor method(s) instead, e.g.:
val myField = 1
get() = if (overridden) 0 else field
Within the accessor, field
refers to the backing field.
You could even write accessor(s) that don’t refer to the backing field, e.g.:
val myField: Int
get() = someOtherField * 2
In this case, the compiler doesn’t generate a backing field at all; just the accessor method(s).
That’s what allows you to write extension properties. You can’t add state to an existing class; but you can effectively add behaviour (as in extension functions), and this can also apply to properties, as long as there’s no backing field. For example:
val Int.reciprocal
get() = 1.0f / this
This defines an extension property to the Int
type. So wherever that’s in scope, you can type e.g. println(1.reciprocal)
just as if Int
s had a new field.
So a Kotlin property is implemented in the traditional Java way: it always has a getter method, and may also have a setter method (if it’s a var
) and/or a backing field
(if that’s needed) — giving you flexibility and interoperability. But at the language level, it looks like a field, with simple syntax and readability. Best of both worlds!