Explain Codes LogoExplain Codes Logo

How to create an instance of an anonymous class of an abstract class in Kotlin?

kotlin
object-expressions
sam-conversions
functional-interfaces
Anton ShumikhinbyAnton Shumikhin·Feb 16, 2025
TLDR

To create an instance of an abstract class in Kotlin, you use an object expression:

abstract class AbstractFoo { abstract fun bar() } val myObject = object : AbstractFoo() { override fun bar() { println("Action of the day: Bar!") } }

In this instance, you override the abstract methods using the braces {} to define your anonymous class. This is the easiest method to create an anonymous class in Kotlin.

Breakdown of object expressions

When to roll with an object expression

Use object expressions when you need a modified class instance for a one-time special occasion, for example, an abstract class or an interface, without declaring a new subclass. The equivalent of dressing up for your cousin's wedding.

Java and Kotlin: Apples and Oranges

In Java, anonymous classes are commonly used for event listeners for GUI elements. Kotlin, however, uses the object keyword, providing cleaner code. Here's a comparison:

// Java way Window.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { System.out.println("I'm Java and I've been clicked."); } });
// Kotlin way window.addMouseListener(object : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { println("I'm Kotlin. Nice clicking!") } })

You can see the Kotlin code has left out the superfluous sugar, simplifying the syntax.

Single Abstract Method (SAM) conversions

For Singular Sensation interfaces a.k.a. functional interfaces that have only a single method, Kotlin has a neat trick: SAM conversions. This uses a lambda expression for neater code.

// No SAM conversion val runnable = object : Runnable { override fun run() { println("Run like there's a prize at the end of this loop!") } } // With SAM conversion val runnable = Runnable { println("Running with ease courtesy of SAM!") }

Note: SAM conversion is available with Java interfaces in Kotlin, but not Kotlin's own interfaces.

Advanced scenarios

Joining two interface parties

Kotlin lets you implement multiple interfaces within an anonymous class:

interface A { fun doSomethingA() } interface B { fun doSomethingB() } val myObject = object : A, B { override fun doSomethingA() { println("Doing something A-mazing!") } override fun doSomethingB() { println("Making something B-rilliant!") } }

Doppelgänger event: extending a class and implementing an interface

Kotlin lets you extend a class and implement an interface at the same time within an anonymous class, effectively solving the problem by proudly wearing both hats!

open class C { open fun foo() {} } interface D { fun bar() } val myObject = object : C(), D { override fun foo() { println("Overriding method in C. Re-defining foo. Don't worry, it will still rhyme with moo.") } override fun bar() { println("Implementing method bar from D... and it's not in a drinking establishment.") } }

Property override in anonymous classes

You can override properties in Kotlin's anonymous classes, opening the door to per-instance customization.

abstract class Vehicle { abstract val numberOfWheels: Int abstract fun ride() } val bike = object : Vehicle() { override val numberOfWheels = 2 override fun ride() { println("Riding on $numberOfWheels wheels and not in a sidecar!") } }

Be aware and beware!

SAM conversions and Kotlin interfaces

A common pitfall is trying to apply SAM conversions to Kotlin-defined interfaces. It's not currently possible:

// This won't compile in Kotlin val kotlinInterfaceInstance = KotlinSingleMethodInterface { /* lambda */ }

To reach similar functionality in Kotlin, consider using functional types or inline classes.

Inline functions and object expressions

Object expressions are a no-no inside inline functions, unless they implement an interface marked as a functional interface with the fun keyword:

inline fun inlineFoo(crossinline action: () -> Unit) { val myObject = object : Runnable { override fun run() = action() } // Party spoiler: Object literal expressions are forbidden in inline functions }

A simple workaround is to use a lambda expression with a functional interface.

Property initialization in object expressions

Properties in an object expression get initialized when the class is instantiated. Be cautious!

abstract class SomeAbstractClass { abstract val someProperty: String } val myObject = object : SomeAbstractClass() { override val someProperty = computeExpensiveValue() // Caution: Be mindful initializing in an incomplete instance }