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

Что такое Override?

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

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

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

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

Override - переопределение методов

Override (переопределение) - это когда подкласс предоставляет свою реализацию метода, который уже определён в суперклассе или интерфейсе. Это один из основных механизмов полиморфизма.

Синтаксис

// Суперкласс
open class Animal {
    open fun makeSound() {
        println("Some generic sound")
    }
}

// Подкласс переопределяет метод
class Dog : Animal() {
    override fun makeSound() {
        println("Woof!")
    }
}

// Использование
val animal: Animal = Dog()
animal.makeSound()  // выведет "Woof!", не "Some generic sound"

Важные правила Override

1. Метод должен быть open

В Kotlin все классы и методы final по умолчанию. Чтобы переопределить метод, он должен быть помечен как open.

// ERROR - нельзя переопределить
class Parent {
    fun someMethod() { }
}

class Child : Parent() {
    override fun someMethod() { }  // compilation error
}

// OK - метод открыт для переопределения
open class Parent {
    open fun someMethod() { }
}

class Child : Parent() {
    override fun someMethod() { }
}

2. Сигнатура должна совпадать

Параметры, тип возвращаемого значения должны быть идентичны.

open class Base {
    open fun process(x: Int): String {
        return x.toString()
    }
}

class Derived : Base() {
    // OK - совпадает сигнатура
    override fun process(x: Int): String {
        return "Number: $x"
    }
    
    // ERROR - разная сигнатура
    // override fun process(x: String): String { }
    
    // ERROR - разный тип возврата
    // override fun process(x: Int): Int { }
}

3. Переопределение свойств

open class Shape {
    open val sides: Int = 0
}

class Triangle : Shape() {
    override val sides: Int = 3
}

class Square : Shape() {
    override val sides: Int = 4
}

Полиморфизм через Override

Основной смысл Override - это полиморфизм. Один метод, разные реализации.

open class Vehicle {
    open fun start() {
        println("Vehicle starting")
    }
}

class Car : Vehicle() {
    override fun start() {
        println("Car engine starts: vroom!")
    }
}

class Bicycle : Vehicle() {
    override fun start() {
        println("Let me pedal...")
    }
}

fun startVehicles(vehicles: List<Vehicle>) {
    for (vehicle in vehicles) {
        vehicle.start()  // вызывает нужную реализацию
    }
}

// Использование
val vehicles = listOf(
    Car(),
    Bicycle(),
    Car()
)
startVehicles(vehicles)
// Car engine starts: vroom!
// Let me pedal...
// Car engine starts: vroom!

Override в интерфейсах

interface Shape {
    fun area(): Double
    fun perimeter(): Double
}

class Circle(val radius: Double) : Shape {
    override fun area(): Double = Math.PI * radius * radius
    override fun perimeter(): Double = 2 * Math.PI * radius
}

class Rectangle(val width: Double, val height: Double) : Shape {
    override fun area(): Double = width * height
    override fun perimeter(): Double = 2 * (width + height)
}

Super - вызов метода суперкласса

Иногда нужно вызвать оригинальную реализацию из суперкласса.

open class Parent {
    open fun greet() {
        println("Hello from Parent")
    }
}

class Child : Parent() {
    override fun greet() {
        super.greet()  // вызываем родительский метод
        println("Hello from Child")
    }
}

val child = Child()
child.greet()
// Hello from Parent
// Hello from Child

Практический пример - ViewModel

// Базовый ViewModel
open class BaseViewModel : ViewModel() {
    protected val _loading = MutableLiveData<Boolean>()
    val loading: LiveData<Boolean> = _loading
    
    open fun onCleared() {
        super.onCleared()
        log("ViewModel cleared")
    }
}

// Конкретный ViewModel переопределяет поведение
class UserViewModel : BaseViewModel() {
    private val userRepository = UserRepository()
    
    override fun onCleared() {
        super.onCleared()  // вызываем базовую реализацию
        userRepository.cleanup()
    }
}

Практический пример - Adapter для RecyclerView

// Базовый адаптер
abstract class BaseRecyclerAdapter<T> : RecyclerView.Adapter<BaseRecyclerAdapter.BaseViewHolder>() {
    protected var items: List<T> = emptyList()
    
    open fun setItems(newItems: List<T>) {
        items = newItems
        notifyDataSetChanged()
    }
    
    abstract inner class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        abstract fun bind(item: T)
    }
}

// Конкретный адаптер для пользователей
class UserAdapter : BaseRecyclerAdapter<User>() {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) 
        = UserViewHolder(LayoutInflater.from(parent.context)
            .inflate(R.layout.item_user, parent, false))
    
    override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
        (holder as UserViewHolder).bind(items[position])
    }
    
    override fun getItemCount() = items.size
    
    inner class UserViewHolder(itemView: View) : BaseViewHolder(itemView) {
        override fun bind(item: User) {
            itemView.textView.text = item.name
        }
    }
}

Вещи, которые нельзя Override

// Нельзя переопределить final методы
open class Parent {
    final override fun doNotOverride() { }  // final - не переопределять
}

// Нельзя переопределить private методы
open class Parent {
    private fun privateMethod() { }  // private - невидим подклассам
}

// Нельзя переопределить static методы (в Kotlin их нет, но есть companion object)
open class Parent {
    companion object {
        fun staticMethod() { }  // companion objects - не переопределяют
    }
}

Проверка при Override

// Можно использовать аннотацию @Override для проверки
open class Parent {
    open fun test() { }
}

class Child : Parent() {
    @Override  // подсказывает, что это override
    override fun test() { }
}

Вывод

Override (переопределение):

  • Позволяет подклассу предоставить свою реализацию метода
  • Основа полиморфизма в OOP
  • Метод должен быть помечен open
  • Сигнатура должна совпадать
  • Можно вызвать super.method() для доступа к родительской реализации
  • Это один из ключевых механизмов для создания гибкой и расширяемой архитектуры