ПрограммированиеKotlin разработчик

Опишите механизм enum-классов в Kotlin: что такое enum class, чем отличается от Java, какие у enum есть особенности и ограничения, как добавлять свой функционал, какие нюансы могут возникнуть при сериализации и сравнении. Приведите пример.

Проходите собеседования с ИИ помощником Hintsage

Ответ.

В Kotlin перечисления (enum class) позволяют объявлять набор ограниченных значений и при этом расширять их методами и свойствами.

Основные моменты:

  • Enum-класс объявляется аналогично Java, но синтаксис более строгий:
    enum class Direction { NORTH, SOUTH, WEST, EAST }
  • Элементы enum — это синглтоны, экземпляры соответствующего подтипа класса.
  • Можно определять дополнительные свойства и методы внутри enum:
    enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF); fun containsRed() = (rgb and 0xFF0000 != 0) }
  • К каждому значению можно обращаться по имени (Color.RED.name), индексу (ordinal) и получать полный список через values().
  • В Kotlin нельзя наследовать enum-классы, но можно реализовывать интерфейсы.
  • Отличие от Java — нельзя явно наследовать классы от enum, нельзя использовать вложенный список;
  • Enum в Kotlin не сериализуется по умолчанию с помощью стандартных средств (например, Gson или Jackson) — необходимы специальные адаптеры/аннотации.

Сравнение enum:

  • Enum сравниваются через == (identity), так как элементы уникальны.
  • При сериализации имена могут меняться, лучше явно задавать значения (storage value pattern).

Вопрос с подвохом.

Можно ли определить абстрактный метод внутри enum-класса в Kotlin, как и в Java, чтобы каждый элемент переопределял его?

Правильный ответ: Да, можно объявить абстрактный метод в enum-стиле, и каждый элемент обязан предоставить свою реализацию!

enum class State { START { override fun next() = RUNNING }, RUNNING { override fun next() = STOPPED }, STOPPED { override fun next() = STOPPED }; abstract fun next(): State }

Примеры реальных ошибок из-за незнания тонкостей темы.


История

При миграции с Java на Kotlin команда попыталась унаследовать новый enum-класс, как обычный класс — выяснилось, что enum нельзя наследовать, нарушив архитектуру. Пришлось полностью менять подход к модульности state-машин.


История

Для хранения значения в базе данных брали имя элемента (enum.name), но с рефакторингом enum переименовали элементы — данные из базы стали несоответствовать новой логике, произошла утрата консистентности (storage value pattern не был реализован).


История

Для сериализации enum-класса через Gson забыли подключить кастомный TypeAdapter. На продуктиве сервис начинал выдавать некорректные значения JSON, потому что стандартный парсер сериализовал не то поле (ordinal или name), и десериализация не совпадала между микросервисами.