Properties

A Kotlin class doesn't have setter or getter methods, yet it doesn't break encapsulation by exposing private fields. The reason is that Kotlin has properties. C# is one of the languages Kotlin drew inspiration from, and the concept of properties is one of the things it took from C#. You can think of properties as fields and methods, all in one place. To the outside users of a property, the syntax looks like they are accessing a public field of a class. Internally in your class, behind a property, you can have get and set accessors or methods and a private backing field. The get and set methods then control how your private field is accessed, thus not breaking encapsulation.

Specifying get and set, as in our case, is optional. If you omit them, then it is implied that the property is both read and write. The compiler generates a private backing field for you in that case. You can also have get only accessor inside a property. This is then considered a read-only property and it cannot be modified from outside. You can also have a set-only property, which is considered write-only and cannot be read from outside. Finally, you can declare your properties with the val keyword, and with this you make them immutable from both inside the containing class and outside the class.

The following examples summarize the get and set accessors.

Get only property, without compiler generated field. We use our own backing _name property here:

private var _name: String = ""

var name: String = _name
get() {
println("name property is being accessed")
return _name
}

Set only property, again without an implicit backing field. The set accessor accepts a parameter that is the same type as the containing property. You can name this parameter (type inference also works on properties and their accessors, so you can omit the type) whatever you like, but the convention is to name it value:

private var _name: String = ""

var name: String = _name
set(value) {
println("name property is being set with value: $value")
_name = value
}

And both get and set accessors. This example uses the implicit compiler generated field, which can be accessed with the field keyword:

var name: String = ""
get() {
println("name property is being accessed")
return field
}
set(value) {
println("name property is being set with value: $value")
field = value
}

Properties always have to be initialized, the same as local variables, unless you use a get and set property without the implicit backing field, as this example shows:

private var _name: String = ""

var name: String //doesn't have to be initialized
get() {
println("name property is being accessed")
return _name
}
set(value) {
println("name property is being set with value: $value")
_name = value
}

Set and get methods can have visibility modifiers. If you don't specify a visibility modifier, then a default, public modifier is implicitly applied. So, it is perfectly fine to have a public property with a private set method. This implies that the property's get method is visible from outside, and the set method is only visible inside the class, that is, only the class itself can modify it:

var name: String = ""
private set

In this example, you can also see that specifying parentheses, a parameter name, and curly braces are optional.

Finally, we have to mention the lateinit keyword. We already said how properties and fields have to be initialized when they are declared. Sometimes when declaring properties, their values will be known only after a class has been initialized. Dependency injection is one of these cases, where usually an inversion of control container sets the values or injects them after the constructor of a class has been called. In that case, you would declare your field as nullable and initialize it with null. But, then you would have to use null safety operators, even though you know that the field is never null. To save you from these kinds of situations, Kotlin offers the lateinit keyword. It can only be applied to properties and fields. The keyword allows you to have a member declared, but not initialized:

private lateinit var name: String

Lateinit is allowed only on reference types and non-null properties. You'll get a compiler error if you put lateinit on a primitive or nullable property:

private lateinit var birthYear: Int // compiler error
private lateinit var lastName: String? // compiler error

If you try to use a lateinit property that has not been initialized, Kotlin will throw a runtime exception. You can check whether a member has been initialized with the isInitialized extension function. The function has to specify a receiver and property. In the following example, the this keyword means the receiver is the class we are calling the function, and after two colons comes the property:

fun checkIfLateinitSet() {
val initialized = this::name.isInitialized
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.237.79