(This answer starts with some general info about Kotlin properties, as there seems to be general confusion about them.)
The main conceptual difference between Kotlin and Java is that in Java, the fundamental thing is the field, while in Kotlin the fundamental thing is the accessor method(s).
So in Java, you define a field. You can then define explicit getter and/or setter methods for it, if needed. The language doesn't have a concept of ‘property’, nor does it define any explicit connection between the accessors and the field; but there's a long-standing convention in the accessor method names (deriving originally from JavaBeans) that almost everyone follows.
This is clear, but long-winded. And because it's only a convention, the language doesn't force you to match fields with accessors: you can have accessors with different types, setters without getters and vice versa, or even accessors with no field. (Some of those things are desirable, but others are more likely to cause bugs and confusion!)
Kotlin, however, takes the view that the accessors are the important thing. (This is an example of the general principle that you should program to the interface, not caring about how it may be implemented.) In effect, a property is its accessor(s). As long as you have a getter method, then you can get the property's value; and as long as you have a setter method, then you can set it too.
Because getters and setters are usually trivial, Kotlin defines them implicitly unless you tell it otherwise. So when you write:
val myProperty = 1
then Kotlin creates:
- A private field called
myProperty, with the type inferred as Int, and initialised to the value 1.
- A getter method called
getMyProperty(), with public scope (as that's the default), returning an Int.
That's just what you'd do in Java, only more concise.
What's different is that whenever you refer to the property, you're calling the accessor method, not accessing the field directly. (That's why it's called a backing field — its only purpose is for the accessor(s) to use.)
Of course, the effect is identical unless you override the accessor. For example:
val myProperty = 1
get() {
LOG.info("Getting value of myProperty = $field")
return field
}
(field is a special keyword within getters and setters, referring to their backing field.)
As before, this generates a field and a getter method; but the getter method is specified in the code and not autogenerated.
(I haven't referred to mutable properties or setters, but the principle there is the same: if the property is a var, then you get an autogenerated or explicit setter method too. One Java possibility that Kotlin doesn't support is write-only properties, where some scope can see a setter but no getter. But those are rarely used; you can always use a normal method to set them, which is probably clearer.)
There's one more case to consider. In Java, a getter method can exist on its own, without a corresponding field. (It must then get its value from some other source — maybe by performing a calculation on other fields, or getting it from another object, or even using a hard-coded value.)
You can do the same in Kotlin, by overriding the getter (and setter, if mutable) and not referring to the field, e.g.:
val myProperty: Int
get() = someOtherObject.someOtherProperty
In this case, there would be no point in generating a field, because it would never be used! So Kotlin recognises this and generates only the accessor method(s).
It's still a property, because it still has accessor method(s), and the rest of the code can't see any difference. Whether it has a backing field or not is purely an implementation detail.
This question is asking about a ‘backing property’. The official docs use that term for a separate, private property which ‘shadows’ an existing one, as shown in this question. (Thanks to cactustictacs for the reference.)
There are specific situations where a backing property can be useful. For example, suppose you need to refer to a specific type within the class, but expose only a supertype publicly; the private property could be of the specific type, and then the public one could be of the supertype.
However, that's not needed simply to restrict the visibility of a setter method: as the question demonstrates, that can be done explicitly (e.g. by adding private set to the property definition).
(In my experience, backing properties are needed very rarely.)