Введение
Разберемся, в чем основное различие между вложенным и внутренним классами. В Kotlin класс может объявляться внутри другого класса, причем двумя способами.
1. Вложенный класс
Созданием одного класса внутри другого с помощью ключевого слова class
:
class Outer {
val companyName: String = "Huawei"
private val companySecret: String = "Secret"
fun getSomething(): String = ""
class NestedClass {
fun printSomething() {
println("From Nested Class")
}
}
}
fun main() {
println(Outer.NestedClass())
}
Обращаясь в функции main
к внутреннему классу, создавать объект класса Outer
не пришлось.
Дело в том, что вложенные классы создаются статически в фоновом режиме. Поэтому для доступа к ним объекты не нужны.
Это подтверждается точным эквивалентом кода на Java при нажатии show Kotlin bytecode («Показать байт-код Kotlin»):

Как видите, вложенные классы преобразуются в static final class в фоновом режиме.
И они не обращаются к данным и функциям своих суперклассов, а сохраняются в фоновом режиме как static final:

Вложенный класс не обращается к данным и функциям класса Outer
, потому что последний еще не появился в памяти:

Когда мы добираемся до вложенного класса, объект класса Outer
не нужен. Вот почему класс Outer
не сохраняется в памяти и нельзя обратиться к его функциям и данным из вложенного класса.
2. Внутренний класс
Созданием внутри класса нового класса с помощью ключевого слова inner
:
class Outer2 {
val companyName: String = "Huawei"
private val companySecret: String = "Secret"
fun getSomething(): String = ""
inner class InnerClass {
fun printSomething() {
println("From Inner Class")
}
}
}
fun main() {
println(Outer2().InnerClass())
}
На этот раз, добираясь до внутреннего класса в функции main
, объект класса Outer
создали. Дело в том, что внутренние классы не сохраняются статически в фоновом режиме, а создаются, как обычные классы.
Это видно в эквиваленте Kotlin-кода на Java:

Как видите, внутренние классы создаются в фоновом режиме, как обычный класс. Поэтому мы обращаемся к значениям и функциям класса Outer
в классе Inner
:

Потому что класс Outer
уже должен быть в памяти для обращения к классу Inner
:

Заключение
Вложенные классы — это специальные классы, которые сохраняются в фоновом режиме как static final и не обращаются к значениям и функциям класса Outer
.
Внутренние классы обращаются к данным и функциям класса Outer
, поскольку в фоновом режиме сохраняются, как обычный класс.
Читайте также:
- Утилитные классы в Kotlin с точки зрения Java-разработчика
- Как написать чистый код, который легко читать
- Как избежать утечек памяти с помощью Kotlin
Читайте нас в Telegram, VK и Дзен
Перевод статьи Hüseyin Özkoç: 👨🏼💻Kotlin Nested Class and Inner Class