Объявление свойств, геттеры и сеттеры в Kotlin

Объявление свойств

Свойства в классах Kotlin могут быть объявлены либо изменяемыми с помощью ключевого слова var, либо доступными только для чтения с помощью ключевого слова val.

class Address {
    var name: String = "Holmes, Sherlock"
    var street: String = "Baker"
    var city: String = "London"
    var state: String? = null
    var zip: String = "123456"
} 

Чтобы использовать свойство, просто обратитесь к нему по имени:

fun copyAddress(address: Address): Address {
    // в Kotlin нет ключевого слова new
    val result = Address() 
    result.name = address.name // вызываются методы доступа
    result.street = address.street
    // ...
    return result
} 

Геттеры и сеттеры

Полный синтаксис объявления свойства:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]

Инициализатор, геттер и сеттер не обязательны. Тип свойства является необязательным, если его можно вывести из инициализатора (или из возвращаемого типа получателя, как показано ниже).

Примеры:

// ошибка: требуется явный инициализатор, 
// подразумеваются методы получения и установки по умолчанию
var allByDefault: Int? 

// имеет тип Int, геттер и сеттер по умолчанию
var initialized = 1 

Полный синтаксис объявления свойства только для чтения отличается от изменяемого по двум причинам: он начинается с val вместо var и не допускает установщика (сеттер):

// имеет тип Int, геттер по умолчанию, 
// должен быть инициализирован в конструкторе
val simple: Int? 

// имеет тип Int и получатель (геттер) по умолчанию
val inferredType = 1 

Мы можем определить собственные средства доступа для свойства. Если мы определим пользовательский метод получения (custom getter), он будет вызываться каждый раз, когда мы обращаемся к свойству (это позволяет нам реализовать вычисляемое свойство). Вот пример пользовательского получателя:

val isEmpty: Boolean
    get() = this.size == 0

Если мы определим настраиваемый сеттер, он будет вызываться каждый раз, когда мы присваиваем значение свойству. Пользовательский сеттер выглядит так:

var stringRepresentation: String
    get() = this.toString()
    set(value) {
        // анализирует строку и 
        // присваивает значения другим свойствам
        setDataFromString(value) 
    }

По соглашению, имя параметра установки - value, но вы можете выбрать другое имя, если хотите.

Начиная с Kotlin 1.1, вы можете опустить тип свойства, если он может быть выведен из получателя:

// имеет тип Boolean
val isEmpty get() = this.size == 0 

Если вам нужно изменить видимость метода доступа или аннотировать его, но не нужно изменять реализацию по умолчанию, вы можете определить метод доступа, не определяя его тело:

var setterVisibility: String = "abc"
    private set 
    // сеттер частный и имеет реализацию по умолчанию
 
var setterWithAnnotation: Any? = null
    @Inject set // аннотировать сеттер с помощью Inject

Резервные поля (Backing Fields)

В Kotlin поле используется только при необходимости как часть свойства для хранения его значения в памяти. Поля не могут быть объявлены напрямую. Однако, когда объекту требуется вспомогательное поле, Kotlin предоставляет его автоматически. На это поле поддержки можно ссылаться в средствах доступа, используя идентификатор field:

// Примечание: инициализатор напрямую назначает резервное поле
var counter = 0 
    set(value) {
        if (value >= 0) field = value
    }

Идентификатор field можно использовать только в методах доступа свойства.

Резервное поле будет создано для свойства, если оно использует реализацию по умолчанию хотя бы одного из методов доступа или если пользовательский метод доступа ссылается на него через идентификатор field.

Например, в следующем случае резервного поля не будет:

val isEmpty: Boolean
    get() = this.size == 0

Резервные свойства (Backing Properties)

Если вы хотите сделать что-то, что не вписывается в эту схему "неявного резервного поля", вы всегда можете вернуться к наличию резервного свойства:

private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap() // Параметры типа выводятся
        }
        return _table ?: throw AssertionError("Установлено значение null другим потоком")
    }

На JVM: доступ к частным свойствам с помощью методов получения и установки (геттеры и сеттеры) по умолчанию оптимизирован, поэтому в этом случае не возникает дополнительных затрат на вызов функций.


Читайте также:


Комментарии

Популярные сообщения из этого блога

Строки в Kotlin

Наследование в Kotlin

Возврат и прыжки в Kotlin