Освой Kotlin играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Интерфейсы в Kotlin ближе к Java 8 и имеют свои особенности. Например, интерфейсы могут содержать объявления свойств.
Класс интерфейса может содержать абстрактные и конкретные функции. Если функция не содержит тела, то она является абстрактной и помечать её как abstract нет необходимости. Интерфейсы могут предоставлять те же преимущества, что и абстрактные классы, но обладают большей гибкостью. Если функция конкретная, то как обычно добавляем тело после фигурных скобок.
Интерфейс не может наследоваться от суперкласса, но может реализовать другие интерфейсы.
Объявим интерфейс с одним абстрактным методом.
interface Clickable
{
fun click()
}
Реализация интерфейса в классе.
class Button : Clickable {
override fun click() = println("I was clicked")
}
Двоеточие после имени класса заменяет ключевые слова implements и extends. В отличие от объявления о наследовании от суперкласса, после имени интерфейса не нужно ставить круглые скобки. Круглые скобки необходимы только для вызова конструктора суперкласса, а у интерфейсов нет конструкторов.
Класс может реализовать несколько интерфейсов, но наследуется только от одного непосредственного суперкласса. Весь этот набор перечисляется через запятую.
// Наследуется от класса Animal и использует интерфейсы Clickable и Focusable
class Cat : Animal(), Clickable, Focusable {
...
}
Ключевое слово override используется вместо аннотации @Override и является обязательным, что снижает количество потенциальных ошибок при неправильном использовании.
У интерфейса можно задать значения по умолчанию. Если в Java 8 для этих целей используется ключевое слово default, то в Kotlin просто указываете тело метода. Добавим в интерфейс ещё один метод, использующий значение по умолчанию.
interface Clickable
{
fun click()
fun meow() = println("Я мяукаю!")
}
Если вас устраивает значение по умолчанию, то реализовывать его в классе не нужно. Либо вы можете изменить поведение метода вместе с click().
Возможна ситуация, когда два разных интерфейса используют одно и то же имя для метода. В этом случае вам придётся их явно реализовывать, даже если их значения по умолчанию вас устраивают.
Добавим ещё один интерфейс.
interface Focusable {
fun setFocus(b: Boolean) =
println("I ${if (b) "got" else "lost"} focus.")
fun meow() = println("В фокусе я рычу. Р-р-р!")
}
class Button : Clickable, Focusable {
override fun click() = println("I was clicked")
override fun meow() {
super<Clickable>.meow()
super<Focusable>.meow()
}
}
Если нужно вызвать только одну унаследованную реализацию, то можете поступить следующим образом.
override fun meow() = super<Clickable>.meow()
Вызываем методы.
val button = Button()
button.meow()
button.setFocus(true)
button.click()
Получим следующее.
Я мяукаю!
В фокусе я рычу. Р-р-р!
I got focus.
I was clicked
Мы вызвали метод meow() один раз, но отработало два раза, так как такой метод встречается в двух интерфейсах.
Можно добавлять в интерфейс абстрактные свойства без указания abstract. Свойствам нельзя присвоить значение и инициализировать.
interface Roamable {
val velocity: Int
}
Можем задать геттер, но его можно переопределить в классе, который будет использовать интерфейс.
interface Roamable {
val velocity: Int
get() = 10
}