Шаг 145.
Основы Kotlin.
Объявление классов. Более пристальный взгляд на свойства var и val

    На этом шаге мы рассмотрим, как интерпретируются свойства var и val.

    В предыдущих шагах вы узнали, что ключевые слова val и var используются для определения свойств класса: val указывает, что свойство доступно только для чтения, var - для записи.

    Может быть, вам интересно, как работает свойство класса Kotlin внутри на JVM.

    Чтобы понять, как реализованы свойства классов, полезно взглянуть на cкомпилированный байт-код JVM, а конкретнее - сравнить байт-код, сгенерированный для каждого свойства в зависимости от формы определения. Создайте новый файл с именем Student.kt. (После упражнения файл нужно удалить.)

    Для начала объявите класс с var-свойством (чтобы оно было доступно для чтения и для записи).

package com.bignerdranch.nyethack

class Student(var name: String)


Рис.1. Объявление класса Student (Student.kt)

    Свойство name в этом примере объявлено в главном конструкторе Student. Вы узнаете больше о конструкторах немного позже, а пока просто рассматривайте конструктор как способ, который в будущем поможет вам изменить порядок создания экземпляров класса. В этом примере конструктор позволяет нам задать имя студента.

    Давайте посмотрим на итоговый байт-код (Tools | Kotlin | Show Kotlin Bytecode):


Рис.2. Итоговый байт-код

    После объявления свойства var name в байт-коде класса Student было сгенерировано четыре элемента: поле name (где будет храниться значение name), метод чтения, метод записи и, наконец, инструкция присваивания полю name значения аргумента name.

    Теперь попробуйте изменить свойство, заменив var на val.

package com.bignerdranch.nyethack

class Student(val name: String)


Рис.3. Замена var на val (Student.kt)

    Посмотрим на получившийся байт-код (особое внимание обратите на исчезнувший код).


Рис.4. Результат замены var на val

    После замены ключевого слова var на val свойство лишилось метода записи.

    Мы также узнали, что для свойства можно объявить свой метод чтения и/или записи. Что изменится в байт-коде, когда вы объявите вычисляемое свойство с методом чтения и без поля для хранения данных? Попробуйте это сделать на уже объявленном классе Student.

package com.bignerdranch.nyethack

class Student() {
    val name: String
        get() = "Madrigal"
}


Рис.5. Делаем name вычисляемым свойством (Student.kt)

    Теперь посмотрим на получившийся байт-код:


Рис.6. Получившийся байт-код

    В этот раз был сгенерирован только один элемент - метод чтения. Компилятор определил, что поле не требуется, так как никакие данные из поля не читаются и не пишутся в него.

    Конкретно эта возможность свойств - вычисление значения, а не просто чтение его из поля - еще одна причина, почему мы используем термины "только для чтения" и "только для записи", а не "изменяемое" и "неизменяемое". Посмотрите еще раз на созданный ранее в REPL класс Dice:

class Dice() {
     val rolledValue
         get() = (1..6).shuffled().first()
 }

    Результат чтения свойства rolledValue из Dice - это случайное значение в интервале от 1 до 6, определяемое каждый раз при обращении к свойству. Это не особо соответствует определению "изменяемое".

    Закончив изучать байт-код, закройте Student.kt и удалите его, щелкнув правой кнопкой мыши на имени файла в окне инструментов проекта и выбрав Delete.

    На следующем шаге мы рассмотрим защиту от состояния гонки.




Предыдущий шаг Содержание Следующий шаг