← Назад к вопросам

В чем разница между inner class и nested class?

1.0 Junior🔥 181 комментариев
#Kotlin основы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между Inner Class и Nested Class в Kotlin

Это важное различие, которое часто путают. Оба — это классы, определённые внутри другого класса, но они работают совершенно по-разному.

Nested Class (静态 вложенный класс)

Nested Class — это статический вложенный класс. Он не имеет доступа к членам внешнего класса.

class Outer {
    private val name = "Outer"
    
    // Nested class (статический)
    class Nested {
        fun getData() {
            // ❌ ОШИБКА! Не можем обратиться к name
            // println(name)
        }
    }
}

// Создание Nested класса
val nested = Outer.Nested()  // не нужен объект Outer!

Характеристики Nested:

  • Не имеет неявной ссылки на Outer
  • Создаётся без объекта внешнего класса
  • Может быть private, protected, public
  • Похож на обычный класс, просто находится в другом классе
  • По умолчанию вложенные классы в Kotlin — Nested

Inner Class (внутренний класс)

Inner Class — это нестатический вложенный класс. Он имеет доступ к членам внешнего класса и содержит неявную ссылку на объект внешнего класса.

class Outer {
    private val name = "Outer"
    
    // Inner class (нестатический)
    inner class Inner {
        fun getData() {
            // ✅ Можем обратиться к name
            println(name)
            // Также доступны private методы
            privateMethod()
        }
    }
    
    private fun privateMethod() {
        println("Private method")
    }
}

// Создание Inner класса
val outer = Outer()
val inner = outer.Inner()  // НУЖЕН объект Outer!
inner.getData()  // Выведет: Outer

Характеристики Inner:

  • Имеет неявную ссылку на Outer
  • Требует объект внешнего класса для создания
  • Может быть private или protected (не public)
  • Содержит скрытое поле this@Outer
  • Требует ключевого слова inner

Таблица сравнения

ПараметрNested ClassInner Class
Ключевое словоclassinner class
Ссылка на Outer❌ Нет✅ Да
СозданиеOuter.Nested()outer.Inner()
Доступ к членам Outer❌ Нет✅ Да
Потребление памятиМеньшеБольше (на ссылку)
Memory leak риск❌ Низкий⚠️ Высокий
СтатичностьСтатичныйДинамический

Практические примеры

Пример 1: Callback pattern

class MainActivity : AppCompatActivity() {
    private val TAG = "MainActivity"
    
    // ❌ ПЛОХО — Inner class может создать memory leak
    inner class DownloadCallback {
        fun onSuccess(data: String) {
            Log.d(TAG, data)  // доступен TAG
        }
    }
    
    // ✅ ХОРОШО — Nested class, нет memory leak
    class NetworkListener {
        fun onConnected() {
            // Не имеет доступа к Activity,
            // но может получить его через параметр
        }
    }
}

Пример 2: Adapter для RecyclerView

class UserActivity : AppCompatActivity() {
    private val viewModel by viewModels<UserViewModel>()
    
    // ✅ ХОРОШО — Nested class
    inner class UserAdapter(val items: List<User>) 
        : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {
        
        override fun onCreateViewHolder(
            parent: ViewGroup,
            viewType: Int
        ): UserViewHolder {
            return UserViewHolder(
                LayoutInflater.from(parent.context)
                    .inflate(R.layout.item_user, parent, false)
            )
        }
        
        override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
            holder.bind(items[position])
        }
        
        override fun getItemCount() = items.size
        
        inner class UserViewHolder(itemView: View) 
            : RecyclerView.ViewHolder(itemView) {
            fun bind(user: User) {
                itemView.textView.text = user.name
                // Можем обратиться к viewModel
                itemView.setOnClickListener {
                    viewModel.selectUser(user)
                }
            }
        }
    }
}

Пример 3: Builder pattern

class Person private constructor(
    val name: String,
    val age: Int,
    val email: String
) {
    // ✅ ХОРОШО — Nested class для Builder
    class Builder {
        private var name = ""
        private var age = 0
        private var email = ""
        
        fun name(value: String) = apply { name = value }
        fun age(value: Int) = apply { age = value }
        fun email(value: String) = apply { email = value }
        
        fun build() = Person(name, age, email)
    }
}

// Использование
val person = Person.Builder()
    .name("Alice")
    .age(30)
    .email("alice@example.com")
    .build()

Memory Leak с Inner Class

Опасность Inner Class — может создать memory leak:

class Activity : AppCompatActivity() {
    private val items = MutableList(1000) { "Item $it" }
    
    // ❌ ПЛОХО — Inner class содержит скрытую ссылку на Activity
    inner class DataLoader {
        fun load() {
            // Имеет доступ к items
            println(items.size)
        }
    }
    
    fun startLoad() {
        // Если долгая операция, Activity не будет удалена из памяти
        val loader = DataLoader()
        // Loader содержит this (Activity) → Activity не может быть GC
    }
}

// Правильный способ:
class Activity : AppCompatActivity() {
    // ✅ Nested class + weakReference
    class DataLoader(val items: List<String>) {
        fun load() {
            println(items.size)
        }
    }
    
    fun startLoad() {
        val loader = DataLoader(listOf("Item 1", "Item 2"))
        // Loader не содержит ссылку на Activity → нет leak
    }
}

Правило выбора

Нужен доступ к членам внешнего класса?
│
├─ ДА → Inner Class
│       ⚠️ Но будь осторожен с memory leak
│
└─ НЕТ → Nested Class
        ✅ Безопаснее и дешевле по памяти

Вывод

  • Nested Class — статический вложенный класс, без ссылки на Outer
  • Inner Class — динамический вложенный класс, с ссылкой на Outer
  • По умолчанию используй Nested (безопаснее и эффективнее)
  • Inner используй только если нужен доступ к Outer членам
  • Осторожно с Inner в долгоживущих объектах (риск memory leak)