Найти тему

Урок 17: Сеттеры и геттеры в Kotlin (setter, getter)

Оглавление
Видео версия урока:
https://youtu.be/8DGWIU3Qvok


Общие понятия

Из прошлого урока про модификаторы доступа плавно переходим к пониманию сеттеров и геттеров. Когда мы обращаемся к свойству какого-то класса, можно подумать, что мы делаем это напрямую. Однако, это не так. Kotlin под капотом генерирует так называемые сеттеры и геттеры. Это методы с помощью которых мы можем получать и изменять свойства. По аналогии с теми фукнциями, что мы сами писали на прошлом уроке, только на уровне языка. Напомню, мы создали getNumberOfPages() и setNumberOfPages(), чтобы получать и задавать значение количества страниц.

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

-2
-3

Повторюсь, Kotlin в местах взаимодействия со свойством под капотом создает сеттеры и геттеры. Когда обращаемся к свойству – создается геттер, когда поставляем в него новое значение – сеттер. И такие сеттеры и геттеры при необходимости можно кастомизировать. То есть добавлять новые условия или данные при инициализации.

Геттер

Мы можем написать их явно. Для этого переходим в созданный класс и под свойством nerveSignalLevel сначала пропишем геттер. Это просто функция get(). После нее через равно пишем то значение, которое она будет возвращать при чтении этой переменной у экземпляра класса.

Реализация по умолчанию

Мы можем отдавать то значение, которым проинициализировали переменную по умолчанию. Делается это с помощью ключевого слова field. Оно передает то поле, для которого мы явно прописываем геттер. Если навести на слово курсор, увидим полное название нашей переменной. А если кликнуть, среда разработки подсветит относящуюся к нему переменную. Это реализация по умолчанию, которую прописывать явно не имеет смысла. Именно поэтому среда разработки подсвечивает геттер волнистой линией и предлагает удалить его как избыточный.

-4

Произвольное значение

Другая ситуация, когда можно указать произвольное значение. Тогда оно и только оно будет возращаться при обращении к полю класса. Например, у нас переменная хранит 200, если тут проставим 250, запустив программу, увидим в консоли это значение.

-5

Сеттер

Реализация для нового значения

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

-6

value в скобках – это объявленный параметр обычной функции, в него будет поступать значение. Название в принципе может быть любым. Тип автоматически будет таким же, как у значения переменной по умолчанию. Указывать его не обязательно, но для наглядности выведем его принудительно с помощью контекстного меню.

Ключевое слово field уже известно, его можно считать полем самого класса, для которого пишем сеттер. И ему присвамиваем поступающее в функцию значение из value. Мы написали реализацию сеттера по умолчанию. Для порядка проверим, передав какое-то значение в объект. Но сначала нужно откатить геттер до стандартной реализации, иначе он всегда будет возвращать 250.

-7

Кастомизация

Хорошо. Для кастомизации вместо value можно поставить какое-либо значение. Но предлагаю воспроизвести более осмысленную ситуацию. Пропишем дополнительную логику. Например, добавим Boolean переменную isTranslated со значением по умолчанию false. Ее смысл в том, что при достаточном уровне нервного сигнала Вавилонская рыбка справляется с переводом и переменная принимает значение true. И эту проверку можно добавить в сеттер.

-8

Теперь, если задать значение нервного сигнала больше 300, переменной isTranslated автоматически присвоится значение true. Посмотри как это выглядит.

-9

Итак, какие видим логи в консоли. Изначальное значение сигнала 200, isTranslated false. Присваиваем новое значение сигнала 400. Сеттер отрабатывает с методом распечатки isTranslated = true и проверяем поля заново. Сигнал 400 и isTranslated true.

Ну и для порядка кастомизируем геттер. Изменение его логики может пригодиться, когда при получении нужно, например, дополнительно вычислять значение. Воспроизведем такое поведение.

Добавим целочисленное свойство с коэффициентом изменения сигнала. Так как он может отсутствовать вовсе, сделаем свойство нуллабельным.

В логику геттера добавим сначала проверку на null. Если коэффициент не null, возвращаем поле с уровнем заданного сигнала помноженное на коэффициент. Иначе просто возвращаем field.

-10

Убедимся, что все работает. Создадим еще два объекта с разными коэффициентами. Теперь в консоль должен вывестись сначала уровень сигнала по умолчанию, затем с коэффициентом 2 и 21. Геттер отрабатывает корректно.

-11

Остается только сказать, что обязательно нужно использовать field и не пытаться использовать вместо него саму переменную класса. В противном случае произойдет рекурсивный (зацикленный) вызов этой переменной.

Дополнительные материалы

🔹 Тесты и практика по этому уроку: https://t.me/KotlinBasicsBot
🔹
Код из всех уроков в личном канале: https://t.me/ievetrov_dev
🔹
Бесплатный курс по Android: https://clck.ru/376Zab
🔹
Вопросы к собеседованию Android: https://t.me/AndroidSprint_Interview
🔹
VK: https://vk.com/ievetrov.development