В Kotlin ключевое слово super используется для обращения к реализации метода или свойства суперкласса либо реализуемого интерфейса. В отличие от Java, Kotlin позволяет явно указать, через какой интерфейс или класс вызвать реализацию метода, что особенно важно при "конфликте" нескольких интерфейсов с одинаковыми методами.
Особенность: Если класс реализует несколько интерфейсов, в которых определён метод с одинаковым сигнатурой и есть реализация по умолчанию, то необходимо явно указать, какую реализацию использовать.
Пример:
interface A { fun foo() = println("A") } interface B { fun foo() = println("B") } class C : A, B { override fun foo() { super<A>.foo() // Явно вызываем A.foo super<B>.foo() // Явно вызываем B.foo } }
Это не поддерживается в Java напрямую (Java не разрешает интерфейсам иметь поля/реализацию методов до Java 8, и даже в Java 8 — механизмы другие).
"Можно ли в Kotlin обратиться к реализации метода суперкласса через несколько уровней наследования?"
super<Intermediate>.foo(), но это не так — обращаться можно только к непосредственному суперклассу или интерфейсу,
который реализует данный метод напрямую.Пример:
open class Base { open fun foo() = println("Base") } open class Mid : Base() { override fun foo() { println("Mid"); super.foo() } } class Child: Mid() { override fun foo() { super.foo() // вызовет Mid.foo() // super<Base>.foo() — ошибка компиляции } }
История
В большом проекте интерфейсы
LoggerиAuditorоба определяли методrecord(). При реализации класса, наследующего оба интерфейса, программист не переопределил явноrecord(), в итоге возникла ошибка компиляции "Class must override public open fun record()". Пришлось реализовать метод вручную и явно делегировать в соответствующий интерфейс.
История
При попытке вызывать реализованный метод суперкласса через несколько промежуточных слоёв (например,
super<Base>.foo()), возникала ошибка компиляции. Разработчик не знал ограничения Kotlin и не мог понять, почему прямой вызов невозможен.
История
После обновления API один из интерфейсов добавил реализацию функции по умолчанию, совпадающую с другим интерфейсом. Старый код больше не компилировался из-за конфликта реализаций — пришлось явно разрешать конфликт, реализуя метод самому и выбирать, какие реализации суперинтерфейсов вызывать внутри себя.