Создание анонимного класса от абстрактного в Kotlin

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для инициализации экземпляра абстрактного класса в Kotlin используется объектное выражение:

kotlin
Скопировать код
abstract class AbstractFoo {
    abstract fun bar()
}

val myObject = object : AbstractFoo() {
    override fun bar() {
        println("Действие дня: Bar!")
    }
}

В приведенном примере мы переопределяем абстрактный метод, оформляя его реализацию с помощью фигурных скобок, так создается анонимный класс.

Кинга Идем в IT: пошаговый план для смены профессии

Разбор объектных выражений

В каких случаях стоит использовать объектное выражение

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

Отличие Kotlin от Java

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

Java
Скопировать код
// Подход Java
Window.addMouseListener(new MouseAdapter() {
    public void mouseClicked(MouseEvent e) {
        System.out.println("Я Java, и меня кликнули.");
    }
});
kotlin
Скопировать код
// Подход Kotlin
window.addMouseListener(object : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
        println("Я Kotlin. Классный клик!")
    }
})

Kotlin отсекает излишние детали, упрощая чтение кода.

Преобразование SAM (Single Abstract Method)

Для функциональных интерфейсов с единственным методом Kotlin предлагает возможность SAM-преобразования:

kotlin
Скопировать код
// Без SAM-преобразования
val runnable = object : Runnable {
    override fun run() {
        println("Бегите, как будто за финишной чертой вас ждёт приз!")
    }
}

// С SAM-преобразованием
val runnable = Runnable { println("Я бегу легко и непринуждённо, благодаря SAM!") }

Однако стоит отметить, что SAM-преобразование доступно только для интерфейсов Java, а не для тех, что определены в Kotlin.

Продвинутые сценарии

Реализация нескольких интерфейсов

В Kotlin вы можете реализовать несколько интерфейсов одновременно при помощи одного анонимного класса:

kotlin
Скопировать код
interface A {
    fun doSomethingA()
}

interface B {
    fun doSomethingB()
}

val myObject = object : A, B {
    override fun doSomethingA() {
        println("Я занимаюсь делом A!")
    }

    override fun doSomethingB() {
        println("И занимаюсь делом B тоже!")
    }
}

Наследование и интерфейсы вместе

В Kotlin один анонимный класс может расширить существующий класс и реализовать интерфейс:

kotlin
Скопировать код
open class C {
    open fun foo() {}
}

interface D {
    fun bar()
}

val myObject = object : C(), D {
    override fun foo() {
        println("Переопределяю foo из C. Не волнуйтесь, всё будет рифмоваться с moo.")
    }

    override fun bar() {
        println("И реализую bar из D. И это не шутка.")
    }
}

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

В анонимных классах Kotlin также разрешается переопределение свойств, что позволяет индивидуализировать экземпляр:

kotlin
Скопировать код
abstract class Vehicle {
    abstract val numberOfWheels: Int
    abstract fun ride()
}

val bike = object : Vehicle() {
    override val numberOfWheels = 2
    override fun ride() {
        println("Еду на $numberOfWheels колёсах, но это не велосипед!")
    }
}

Визуализация

Создание анонимного класса на основе абстрактного класса в Kotlin можно сравнить с подготовкой импровизированного представления:

kotlin
Скопировать код
// Ваш абстрактный шаблон класса:
abstract class AbstractActor {
    abstract fun perform()
}

// Ваш уникальный сценарий:
val actor = object : AbstractActor() {
    override fun perform() {
        // Проявите свой талант!
    }
}

AbstractActor — это ваша творческая площадка. С помощью perform вы становитесь звездой своего уникального шоу.

Будьте внимательны!

SAM-преобразование и интерфейсы Kotlin

Распространенная ошибка — это применение SAM-преобразования к интерфейсам Kotlin. Это невозможно без использования функциональных типов или inline-классов.

Inline-функции и объектные выражения

В inline-функциях нельзя использовать объектные выражения, если они не реализуют fun-интерфейс:

kotlin
Скопировать код
inline fun inlineFoo(crossinline action: () -> Unit) {
    val myObject = object : Runnable {
        override fun run() = action()
    }
    // Недопустимо: литеральные выражения объектов запрещены в inline-функциях 
}

Лямбды могут служить альтернативой для обхода этого ограничения.

Инициализация свойств в объектных выражениях

Свойства в объектном выражении инициализируются при создании экземпляра, поэтому требуется внимательность.

kotlin
Скопировать код
abstract class SomeAbstractClass {
    abstract val someProperty: String
}

val myObject = object : SomeAbstractClass() {
    override val someProperty = computeExpensiveValue()
    // Внимание: инициализация происходит при создании экземпляра
}

Полезные материалы

  1. Официальная документация Kotlin – подробное описание использования объектных выражений и анонимных классов.
  2. Статья на Medium – содержит ценные советы по переводу кода из Java в Kotlin.
  3. Kotlin Playground – обучение Kotlin на практических примерах.
  4. Baeldung – вводное руководство по анонимным внутренним классам в Kotlin.
  5. Руководство для разработчиков Android – полный материал о Kotlin в контексте Android.
  6. Kodeco – для тех, кто стремится углубить свои знания Kotlin.