Интерфейс Kotlin поддерживает реализацию по умолчанию. Это означает, что у нас может быть реализация по умолчанию для всех свойств и функций, определенных в интерфейсе.

Споры:
Многие разработчики не приветствуют реализацию интерфейса по умолчанию. Мы не будем обсуждать плюсы и минусы, но нас больше интересует, как Kotlin этого добился.

Примечание. Для простоты блоки кода Java , используемые в этой статье, представляют собой декомпилированный Java-эквивалент сгенерированного байт-кода Kotlin компилятор.

Давайте начнем

Давайте возьмем базовый интерфейс Wheels с реализациями по умолчанию в качестве примера для понимания предмета.

interface Wheels {
    fun getNumberOfWheels(): Int = 3
}

Этот интерфейс позволяет нам пропустить реализацию в классе Kotlin 😎.

class KotlinCar : Wheels

Проблема Java

Java заставляет нас реализовывать все методы интерфейса, даже если есть реализация по умолчанию из интерфейса kotlin.

Почему нас это волнует?
Хотя мы любим kotlin, иногда мы вынуждены поддерживать устаревший код с помощью Java.

Итак, как нам использовать реализацию по умолчанию в классе Java?

DefaultImpls 🎉

DefaultImpls - это класс, созданный компилятором для хранения реализаций по умолчанию. Он может содержать методы по умолчанию для функций и значения их параметров по умолчанию. Это причина, по которой koltin изначально поддерживает методы по умолчанию. И почему он может работать даже на Java 6.

Забавный факт

  • DefaultImpls можно ссылаться непосредственно из источников Java 👍, но не из Kotlin
  • Вам не разрешено называть вложенный тип как DefaultImpls в интерфейсе kotlin 🙅‍♂️. "Проверь это"
  • @JvmName тоже не поможет

Возьмем пример интерфейса Wheels.

Код Java (декомпилированный байт-код) показывает, что создан статический класс DefaultsImpls. Этот класс будет создан только при наличии хотя бы одной реализации по умолчанию.

В данном случае - реализация по умолчанию getNumberOfWheels(). Он реализован как статический метод с тем же именем, типом возвращаемого значения и параметром instance. $this ссылки в теле функции относятся к параметру instance.

Так как же котлин делает трюк?

Если реализующий класс не определяет getNumberOfWheels(), синтетический компилятор генерирует класс, просто указывающий на этот статический метод.

А как насчет Java?

Вы можете реализовать то же поведение в java, обратившись к DefaultImpls, но вы по-прежнему вынуждены реализовывать методы.

Хорошая новость в том, что вы по-прежнему можете получить доступ к реализации по умолчанию, обратившись к статическому классу внутри интерфейса.

Примечание. Это общедоступно только при доступе с Java.

Ах! мы также можем сделать то же самое в Kotlin, вызвав super.$functionName(), но класс DefaultImpls не доступен напрямую из Kotlin (это очевидно).

OverKill - Бесполезная реализация

Вот пример: «Я делаю это только потому, что я могу это сделать»

KotlinCar и KotlinCar2 генерируют один и тот же байт-код, поэтому не переусердствуйте. То, что вы можете, не означает, что вам следует.

Ой! Трехколесный автомобиль 🚓 , использованный в примере, был вдохновлен этим видео

Связанная тема: _ 18_ аннотация.