Kotlin: Interface не имеет конструкторов — как создать экземпляр?
Проблема: интерфейсы в Kotlin нельзя инстанциировать как классы
Ошибка возникает, потому что в Kotlin интерфейсы — это не классы. В Java вы можете написать new Interface() { ... }, потому что анонимные классы — это особенность синтаксиса Java. В Kotlin такого синтаксиса нет. Вместо этого используется более лаконичный и безопасный подход — object expression.
Решение: используйте object expression
Чтобы создать анонимную реализацию интерфейса в Kotlin, нужно использовать ключевое слово object с двоеточием и именем интерфейса. Вот правильный код:
interface Drawable {
fun draw()
}
fun main() {
val d = object : Drawable {
override fun draw() {
println("Рисую")
}
}
d.draw() // Вывод: Рисую
}
Почему это работает?
object : Drawable— это анонимный объект, который реализует интерфейсDrawable.- Внутри фигурных скобок мы переопределяем все абстрактные методы интерфейса (в данном случае
draw()). - Этот объект можно использовать как обычную переменную, передавать в функции и т.д.
Дополнительные примеры
Если интерфейс имеет несколько методов, их все нужно переопределить:
interface Clickable {
fun click()
fun doubleClick()
}
val button = object : Clickable {
override fun click() = println("Клик")
override fun doubleClick() = println("Двойной клик")
}
Вы также можете использовать object expression для реализации нескольких интерфейсов одновременно:
interface A { fun foo() }
interface B { fun bar() }
val obj = object : A, B {
override fun foo() = println("A")
override fun bar() = println("B")
}
Когда использовать отдельный класс?
Если анонимная реализация вам нужна в одном месте — object expression идеален. Если же реализация переиспользуется в нескольких местах, лучше создать именованный класс:
class Circle : Drawable {
override fun draw() = println("Рисую круг")
}
val c = Circle() // Всё работает
Важное замечание
В отличие от Java, в Kotlin нет ключевого слова new. Всегда используйте object : InterfaceName { ... } для анонимных реализаций. Это не только решает проблему, но и делает код более читаемым и безопасным (например, вы не можете случайно создать экземпляр абстрактного класса).
Альтернативный подход: функциональные интерфейсы (SAM-конверсия)
Если ваш интерфейс содержит только один абстрактный метод (такие интерфейсы называют функциональными или SAM — Single Abstract Method), вы можете использовать более краткий синтаксис с помощью лямбда-выражений. Для этого интерфейс нужно пометить аннотацией fun:
fun interface Drawable {
fun draw()
}
fun main() {
val d = Drawable { println("Рисую") } // Лямбда вместо object expression
d.draw()
}
Этот подход работает только в Kotlin 1.4+ и только для интерфейсов с одним абстрактным методом. Если методов несколько, придётся использовать object expression.
Сравнение подходов
- Object expression — универсальный способ для любых интерфейсов (с любым количеством методов).
- SAM-конверсия — более краткий вариант для функциональных интерфейсов, но требует аннотации
fun interface.
Выбирайте тот способ, который лучше подходит под вашу задачу. Для кода, который вы привели (один метод), SAM-конверсия будет более идиоматичной в современном Kotlin.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги