skip to content

What are the rules for supertypes in a Kotlin object expression, including supplying constructor arguments and combining multiple types?

level: middleimportance: should knowfreq 45%

answer

  1. One class + many interfaces after colon
  2. Superclass args after the type name
  3. Interfaces take no args
  4. Must override all abstract members
  5. super<Type>.member() disambiguates conflicts

basics

~10 s

After the colon you can list one class plus any number of interfaces, separated by commas. If the class has a constructor, you pass its arguments right after the class name, like calling it.

solid answer

~40 s

In `object : Super1(args), Super2, Super3 { ... }`, you may extend at most one open/abstract class and implement any number of interfaces, all listed after the colon and comma-separated. If the superclass has a non-trivial constructor, you supply its arguments immediately after the type name — the same syntax as a class constructor call. Interfaces take no arguments. The anonymous object must satisfy all abstract members from every supertype, overriding them in the body with `override`. If two supertypes declare conflicting members, you must override explicitly and can disambiguate with `super<Type>.member()`. With no supertype at all, `object { }` is allowed and the implicit supertype is `Any`. This mirrors how a normal class declares its supertypes, just inlined at the use site.

code

kotlin · 9 lines
kotlin
interface Closeable2 { fun close() }
open class Resource(val id: Int) { open fun open() = println("open $id") }

val r = object : Resource(7), Closeable2, Comparable<Int> {
    override fun close() = println("close $id")
    override fun compareTo(other: Int) = id - other
}

fun main() { r.open(); r.close(); println(r.compareTo(7)) }

go deeper

for a junior

Knows the body must override the interface methods it implements.

for a middle

States the one-class-plus-many-interfaces rule, where constructor args go, and that all abstract members must be overridden.

for a senior

Handles member conflicts with super<Type> and explains the parallel to normal class supertype declarations.

for a principal

Judges when collapsing several roles into one anonymous object is clean vs when distinct named types are warranted for testability and clarity.

## Supertype list After the colon, an object expression lists its supertypes, comma-separated: ```kotlin interface A { fun a() } interface B { fun b() } open class Base(val name: String) { open fun describe() = name } val obj = object : Base("x"), A, B { override fun a() = println("a") override fun b() = println("b") override fun describe() = "obj:$name" } ``` ### Rules - **At most one class** (it must be `open` or `abstract`); **any number of interfaces**. - **Constructor arguments** for the superclass go right after the class name: `Base("x")`. Interfaces never take arguments. - All **abstract members** from every supertype must be implemented with `override`, or the code won't compile. - **No supertype** is allowed: `object { val x = 1 }` — implicit supertype is `Any`. ## Resolving conflicts If two supertypes provide a member with the same signature, you must **override it explicitly**. Use the qualified `super<Type>` form to call a specific parent implementation: ```kotlin interface Left { fun greet() = "left" } interface Right { fun greet() = "right" } val merged = object : Left, Right { override fun greet() = super<Left>.greet() + super<Right>.greet() } ``` ## Comparison to named classes The supertype rules are identical to a normal class declaration — single class + multiple interfaces, constructor delegation — only inlined. The difference is there is no class name and the instance is produced immediately. ## Gotchas - Trying to extend two classes is a compile error. - Forgetting constructor args for a superclass that needs them is an error. - An anonymous object can also add brand-new members beyond what the supertypes require.

  • Can an object expression extend two classes?
    No. Like any Kotlin class it may extend at most one class but implement any number of interfaces.
  • How do you call a specific parent's default method when two interfaces clash?
    Override the member and use the qualified super call `super<InterfaceName>.method()`.

saying these in an interview costs you the question

  • Claiming you can extend multiple classes
  • Putting constructor args on an interface
  • Forgetting that all abstract members must be overridden
  • Not knowing super<Type> disambiguation exists
  • Saying a supertype is always required

context