Можно ли наследовать enum классы друг от друга в Kotlin
Что проверяют
Понимаете ли вы, почему наследование перечислений невозможно, и знаете ли, чем его заменить.
Как отвечать
Нельзя ни в одну сторону. Перечисление не может наследовать другой класс, потому что оно уже неявно наследует служебный базовый тип перечислений, а множественного наследования классов нет. И наследоваться от перечисления тоже нельзя.
Причина второго запрета содержательная: смысл перечисления в конечном, замкнутом наборе значений, известном на этапе компиляции. Именно на этом держится исчерпывающая проверка ветвлений: компилятор знает все варианты и требует обработать каждый. Разреши наследование, и набор перестанет быть замкнутым, а гарантия исчезнет.
Что перечислению можно:
- реализовывать интерфейсы, причём каждая константа может дать свою реализацию в собственном теле;
- иметь свойства и методы, конструктор с параметрами;
- иметь абстрактный метод, который каждая константа обязана реализовать.
enum class Grade(val years: Int) {
JUNIOR(1) { override fun next() = MIDDLE },
MIDDLE(3) { override fun next() = SENIOR },
SENIOR(5) { override fun next() = SENIOR };
abstract fun next(): Grade
}Если нужна настоящая иерархия, ответ это запечатанный класс или интерфейс. Он даёт то, чего перечислению не хватает:
- варианты могут нести разные наборы данных, а не только отличаться константой;
- вариантов может быть несколько экземпляров, а не по одному;
- при этом набор наследников по-прежнему известен компилятору, поэтому исчерпывающая проверка ветвлений сохраняется.
Отсюда практическое правило: простой набор именованных значений это перечисление, набор состояний с разными данными это запечатанный тип.
Где спотыкаются
Пытаются построить иерархию перечислений.
Не знают, что константа может иметь собственное тело.
Ставят ветку по умолчанию и теряют проверку полноты.
Используют перечисление там, где вариантам нужны разные поля.