How do I create and use companion objects for static-like behavior in Kotlin?

In Kotlin, a companion object is an object declared inside a class that can hold members callable on the class itself, giving you static-like behavior.

Kotlin does not have Java-style static members directly. Instead, you usually use companion object.

Basic example

class User(val name: String) {
    companion object {
        const val DEFAULT_NAME = "Guest"

        fun createDefault(): User {
            return User(DEFAULT_NAME)
        }
    }
}

You can access companion object members using the class name:

fun main() {
    println(User.DEFAULT_NAME)

    val user = User.createDefault()
    println(user.name)
}

Output:

Guest
Guest

Why it feels like static

This:

User.createDefault()

is similar to calling a static method in Java:

User.createDefault();

But internally, Kotlin’s companion object is an actual singleton object associated with the class.

Companion object properties

You can put properties inside a companion object:

class Counter {
    companion object {
        var count = 0

        fun increment() {
            count++
        }
    }
}

Usage:

fun main() {
    Counter.increment()
    Counter.increment()

    println(Counter.count)
}

Output:

2

Named companion objects

A companion object can have a name:

class Database {
    companion object Factory {
        fun connect(): Database {
            return Database()
        }
    }
}

You can still access members through the class name:

val db = Database.connect()

Or through the companion object name:

val db = Database.Factory.connect()

Factory method example

A common use case is creating factory methods:

class Person private constructor(
    val name: String,
    val age: Int
) {
    companion object {
        fun of(name: String, age: Int): Person {
            require(age >= 0) { "Age cannot be negative" }
            return Person(name, age)
        }
    }
}

Usage:

fun main() {
    val person = Person.of("Alice", 30)
    println(person.name)
}

Constants in companion objects

For compile-time constants, use const val:

class ApiConfig {
    companion object {
        const val BASE_URL = "https://api.example.com"
        const val TIMEOUT_SECONDS = 30
    }
}

Usage:

println(ApiConfig.BASE_URL)

const val can only be used with primitive types and String.

Java interoperability

From Java, companion object members are normally accessed through Companion:

class MathUtils {
    companion object {
        fun double(x: Int): Int = x * 2
    }
}

Java usage:

int result = MathUtils.Companion.double(5);

If you want Java callers to use it like a real static method, add @JvmStatic:

class MathUtils {
    companion object {
        @JvmStatic
        fun double(x: Int): Int = x * 2
    }
}

Then Java can call:

int result = MathUtils.double(5);

For constants:

class Constants {
    companion object {
        const val APP_NAME = "MyApp"
    }
}

Java can access this as:

String appName = Constants.APP_NAME;

Companion objects can implement interfaces

Because companion objects are real objects, they can implement interfaces:

interface Parser<T> {
    fun parse(value: String): T
}

class User(val name: String) {
    companion object : Parser<User> {
        override fun parse(value: String): User {
            return User(value)
        }
    }
}

Usage:

fun main() {
    val user = User.parse("Alice")
    println(user.name)
}

You can also pass the companion object where the interface is expected:

fun <T> parseWith(parser: Parser<T>, value: String): T {
    return parser.parse(value)
}

val user = parseWith(User, "Bob")

Here, User refers to the companion object when used as a value.

Key points

  • Use companion object for static-like members.
  • Access members as ClassName.member.
  • Use const val for compile-time constants.
  • Use @JvmStatic if Java callers need static-style access.
  • Companion objects are real singleton objects.
  • Companion objects can have names and implement interfaces.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.