1. Overview

In Java, we have anonymous classes, which allow us to declare and instantiate anonymous classes in a single expression at the point of use.

In this tutorial, we’ll explore the anonymous classes and objects in Kotlin.

2. Introduction to Anonymous Objects

Instances of anonymous classes are called anonymous objects, as an expression – instead of a name – defines them.

Usually, the anonymous objects are pretty lightweight and for one-time use. In Kotlin, anonymous objects are created by object expressions.

We should note that the object expression we’re talking about is not the object declaration to create a single static instance of a type.

In this tutorial, we’ll first look at how to create anonymous objects from a supertype, such as an abstract class. Then, we’ll address an interesting usage: creating anonymous objects from scratch.

Further, we’ll compare Kotlin’s anonymous objects and their counterpart in Java.

For simplicity, we’ll use unit tests’ assertions to verify whether our anonymous objects are working as expected.

Next, let’s see them in action.

3. Creating Anonymous Objects From an Abstract Class

As in Java, we cannot instantiate an abstract class directly in Kotlin, either. For example, let’s say we have an abstract class called Doc:

abstract class Doc(
    val title: String,
    val author: String,
    var words: Long = 0L
) {
    abstract fun summary(): String
}

As we can see in the class above, Doc has a constructor. But if we try to instantiate it directly:

val article = Doc(title = "A nice article", author = "Kai", words = 420) // won't compile!

The compiler will complain: “cannot create an instance of an abstract class“.

However, we can use the object expression to create an object of an anonymous class that inherits Doc:

val article = object : Doc(title = "A nice article", author = "Kai", words = 420) {
    override fun summary() = "Title: <$title> ($words words) By $author"
}

As the code above shows, the object expression syntax for creating an anonymous object from a type is:

object : TheType(...constructor parameters...) { ... implementations ... }

In our example, we’ve implemented the abstract function summary. Now, let’s verify if the article object is what we’re expecting:

article.let {
    assertThat(it).isInstanceOf(Doc::class.java)
    assertThat(it.summary()).isEqualTo("Title: <A nice article> (420 words) By Kai")
}

When we run the test, it passes. So, the article object works as expected.

Apart from abstract classes, we can create anonymous objects from interfaces using a similar syntax. Next, let’s see how it works.

4. Creating Anonymous Objects From an Interface

In Kotlin, as interfaces cannot have constructors, the object expression’s syntax changes to:

object : TheInterface { ... implementations ... }

Next, let’s see an example. First, let’s say we have an interface:

interface Printable {
    val content: String
    fun print(): String
}

Next, let’s create an anonymous object from it:

val sentence = object : Printable {
    override val content: String = "A beautiful sentence."
    override fun print(): String = "[Print Result]\n$content"
}

As the code above shows, our anonymous class has overridden the content property and implemented the print function.

A test can verify that the sentence object works as expected:

sentence.let {
    assertThat(it).isInstanceOf(Printable::class.java)
    assertThat(it.print()).isEqualTo("[Print Result]\nA beautiful sentence.")
}

Next, let’s have a look at another interesting use case of anonymous objects.

5. Defining an Anonymous Object From Scratch

So far, we’ve explored creating anonymous objects of a supertype. Apart from that, in Kotlin, we can still define an anonymous object from scratch. Let’s first look at an example:

val player = object {
    val name = "Kai"
    val gamePlayed = 6L
    val points = 42L
    fun pointsPerGame() = "$name: AVG points per Game: ${points / gamePlayed}"
}

player.let {
    assertThat(it.name).isEqualTo("Kai")
    assertThat(it.pointsPerGame()).isEqualTo("Kai: AVG points per Game: 7")
}

As we can see in the code above, the player variable holds an anonymous object that doesn’t have an explicit supertype.

The object expression to create such an object is pretty simple this time: object { … implementations …}.

Many may think this is something new in Kotlin. We don’t have a counterpart in Java since, in Java, our anonymous class must have a supertype.

Actually, since every class in Java is a subclass of the Object class, the object expression works quite similar to this Java code:

Object player = new Object() {
    String name = "Kai";
    Long gamePlayed = 6L;
    String pointsPerGame() {
        return "$name: AVG points per Game: ${points / gamePlayed}"
    }
};

However, if we’ve defined the player object with the type Object, we cannot access player‘s properties or methods. However, If our Java version is 10 or newer, we can use the var keyword to define the player object. Then we can access its members in the same method:

var player = new Object() {
    String name = "Kai";
   ...
    String pointsPerGame() { ...}
};

player.pointsPerGame();
String playerName = player.name;

In Kotlin, we can use an anonymous object as the return value of a method. Moreover, if the anonymous object is returned by a private method, we can still access its members:

class PlayerService() {
    private fun giveMeAPlayer() = object {
        val name = "Kai"
        val gamePlayed = 6L
        val points = 42L
        fun pointsPerGame() = "$name: AVG points per Game: ${points / gamePlayed}"
    }

    fun getTheName(): String {
        val thePlayer = giveMeAPlayer()
        print(thePlayer.pointsPerGam())
        return thePlayer.name
    }
}

On the other side, Java doesn’t have this feature. This is because if a Java method returns a similar anonymous object, the method must define Object as the return type. Thus, we cannot access the anonymous object’s members.

6. Conclusion

In this article, we’ve addressed how to instantiate an abstract class or interface using object expressions in Kotlin.

Further, we’ve compared the anonymous objects in Kotlin and Java, especially when we define an anonymous object from scratch in Kotlin.

As always, the full source code used in the article can be found over on GitHub.

Comments are closed on this article!