Вложенные (nested) и внутренние (inner) классы в Kotlin применяются для логической группировки и инкапсуляции функционала внутри внешнего класса.
Идея вложенных классов пришла из Java как способ структурировать код и изолировать вспомогательные компоненты внутри основного класса. В Kotlin синтаксис и подход наследованы от Java, но с важными отличиями.
Главная задача — грамотно отделить вспомогательные классы там, где они не должны существовать вне контекста внешнего класса, но при этом требуется разная степень доступа к членам внешнего класса. В Java по умолчанию вложенный класс — это inner class, в Kotlin по умолчанию nested (статический).
В Kotlin по умолчанию объявление класса внутри другого создает статический (nested) класс, то есть этот класс не имеет доступа к членам внешнего класса. Для получения доступа используется ключевое слово inner.
Пример кода:
class Outer { private val secret = "outside" class Nested { fun call() = "nested: no access to Outer.secret" } inner class Inner { fun call() = "inner: can access $secret" } }
Ключевые особенности:
class Nested) по умолчанию не имеет ссылки на экземпляр внешнего класса;inner class Inner) имеет ссылку и может обращаться к членам внешнего класса, даже к приватным;Может ли вложенный (nested) класс обращаться к приватному свойству внешнего класса?
Нет, вложенный класс (по умолчанию) в Kotlin статичен и не содержит ссылки на внешний класс, поэтому не имеет доступа к его свойствам и методам.
Какая разница между inner-классами в Kotlin и Java?
В Java вложенный класс по умолчанию не static и имеет ссылку на внешний. В Kotlin — наоборот; вложенный класс static, только inner-класс получает ссылку на внешний экземпляр.
Можно ли объявить внутренний класс в объекте (object)?
Нет, внутренний класс (inner) не может быть объявлен внутри object, потому что object не может быть инстанцирован.
Разработчик объявляет inner-класс, который не использует свойства внешнего класса:
class Container { inner class Helper { fun help() = "help" } }
Плюсы:
Класс легко получить из внешнего объекта.
Минусы:
Использование inner-класса для реализации доступа к приватному состоянию внешнего класса:
class Auth { private var token: String = "" inner class TokenManager { fun updateToken(new: String) { token = new } } }
Плюсы:
Минусы: