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

Как переопределить метод в классе-наследнике

1.6 Junior🔥 121 комментариев
#Kotlin основы#Архитектура и паттерны

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

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

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

Переопределение методов в классе-наследнике (Override)

Переопределение (override) - это фундаментальная часть полиморфизма в ООП.

Основной синтаксис

open class Animal {
    open fun makeSound() {
        println("Generic animal sound")
    }
}

class Dog : Animal() {
    override fun makeSound() {
        println("Woof!")
    }
}

class Cat : Animal() {
    override fun makeSound() {
        println("Meow!")
    }
}

// Использование
val dog: Animal = Dog()
val cat: Animal = Cat()

dog.makeSound()  // Woof!
cat.makeSound()  // Meow!

Правила переопределения

1. Класс должен быть open

open class Parent {
    open fun method() {}
}

class Child : Parent() {
    override fun method() {}  // OK
}

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

open class Parent {
    fun regularMethod() {}     // final (не переопределяется)
    open fun virtualMethod() {} // можно переопределить
}

class Child : Parent() {
    override fun virtualMethod() {}  // OK
    override fun regularMethod() {}  // ОШИБКА!
}

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

open class Vehicle {
    open val speed: Int = 100
    
    open fun drive() {
        println("Driving at $speed km/h")
    }
}

class Car : Vehicle() {
    override val speed: Int = 200  // Переопределить свойство
    
    override fun drive() {
        println("Car driving at $speed km/h")
    }
}

class Bike : Vehicle() {
    override val speed: Int = 150
}

val car = Car()
car.drive()  // Car driving at 200 km/h

Вызов метода родителя через super

open class Animal {
    open fun makeSound() {
        println("Generic sound")
    }
}

class Dog : Animal() {
    override fun makeSound() {
        super.makeSound()  // Вызвать метод родителя
        println("Woof!")   // Добавить свое поведение
    }
}

// Output:
// Generic sound
// Woof!

Переопределение с разными сигнатурами

// ОШИБКА: сигнатура не совпадает
open class Parent {
    open fun process(value: Int): String {
        return "Processed: $value"
    }
}

class Child : Parent() {
    override fun process(value: Int): String {  // Сигнатура совпадает
        return "Child processed: $value"
    }
    
    // ОШИБКА: это не переопределение, а overload
    fun process(value: String): String {
        return "String: $value"
    }
}

Переопределение в интерфейсах

interface Shape {
    fun getArea(): Double
}

class Circle(val radius: Double) : Shape {
    override fun getArea(): Double {
        return Math.PI * radius * radius
    }
}

class Rectangle(val width: Double, val height: Double) : Shape {
    override fun getArea(): Double {
        return width * height
    }
}

Абстрактные классы

abstract class Animal {
    abstract fun makeSound()  // Must be overridden
    
    fun sleep() {
        println("Sleeping")
    }
}

class Dog : Animal() {
    override fun makeSound() {
        println("Woof!")
    }
    // sleep() наследуется автоматически
}

// ОШИБКА: не переопределил abstract метод
class Bird : Animal() {
    // Compile error: must override makeSound
}

Модификаторы доступа при переопределении

open class Parent {
    open protected fun protectedMethod() {}  // protected
    open fun publicMethod() {}                // public
}

class Child : Parent() {
    override fun protectedMethod() {}  // Может быть public
    override public fun publicMethod() {}  // Явно public
    
    // ОШИБКА: нельзя сузить видимость
    // override private fun publicMethod() {}
}

Переопределение с изменением типа возврата (Covariance)

open class Animal
class Dog : Animal()

open class AnimalFactory {
    open fun create(): Animal {
        return Animal()
    }
}

class DogFactory : AnimalFactory() {
    override fun create(): Dog {  // Более специфичный тип
        return Dog()
    }
}

Практический пример: Lifecycle методы в Activity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
    
    override fun onStart() {
        super.onStart()
        // Инициализировать
    }
    
    override fun onPause() {
        super.onPause()
        // Сохранить состояние
    }
    
    override fun onDestroy() {
        super.onDestroy()
        // Очистить ресурсы
    }
}

Проверка переопределения

open class Parent {
    open fun method() {}
}

class Child : Parent() {
    @Override  // Аннотация (опциональна, но рекомендуется)
    override fun method() {}
}

final переопределение

open class Parent {
    open fun method1() {}
    final override fun method2() {}  // Больше не переопределяется
}

open class Child : Parent() {
    override fun method1() {}
    
    // ОШИБКА: method2 final
    // override fun method2() {}
}

Когда использовать override

✅ Используй override для:

  • Полиморфного поведения
  • Lifecycle методов (onCreate, onStart и т.д.)
  • Реализации интерфейсов
  • Абстрактных методов

❌ Избегай:

  • Нарушения Liskov Substitution Principle
  • Значительного изменения контракта
  • Превращения public в private

Вывод

Оверрайд - это механизм полиморфизма:

  1. Метод в родителе должен быть open
  2. Класс должен быть open
  3. Используй super для вызова родительского метода
  4. Сигнатура должна совпадать
  5. Переброс super.method() при необходимости