Sitemap

Learn Kotlin with me — Companion Objects

3 min readMay 12, 2025

Companion Objects vs Objects, Syntax and Features of Companion Objects

Press enter or click to view image in full size
Photo by Matthew Henry on Unsplash

Kotlin is known for its concise syntax and modern features that help create clean, maintainable code. One such feature is the companion object. In this blog, we’ll explore what companion objects are and why you might use them and provide multiple examples to illustrate them.

What is a Companion Object?

In Kotlin, a companion object is a singleton object that is associated with its enclosing class. It allows you to define members (such as functions or properties) that can be called without creating an instance of that class. If you come from a Java background, you might think of companion objects as an alternative to static members, but with several added benefits.

Companion objects are instantiated when the containing class is loaded, making them similar in spirit to Java’s static initialisers, but with extra flexibility such as implementing interfaces or even extending other classes.

Basic Syntax and Example

Declaring a companion object is simple. You use the companion keyword inside a class. If you don’t name it explicitly, Kotlin assigns it the default name Companion.

class MyClass {
companion object {
const val CONSTANT_VALUE = 42
fun showConstant() {
println("The constant value is $CONSTANT_VALUE")
}
}
}

fun main() {
println(MyClass.CONSTANT_VALUE)
MyClass.showConstant()
}

In this example, we declared a companion object in MyClass that holds a constant and a function. Notice how we can access these members directly using the class name without creating an instance.

Why Use Companion Objects?

Companion objects offer several advantages:

  • Factory Methods: They provide a natural place to define factory methods. This is useful when you want to control the creation of class instances.
  • Constants and Utility Functions: Grouping constants and helper functions together keeps your code organised.
  • Encapsulation: They allow you to encapsulate class-level functionality, reducing global namespace pollution.
  • Interoperability: With annotations like @JvmStatic, companion object members can be exposed as true static methods to Java code.

Example: Factory Method

Let’s see a real-world example where the companion object is used to create instances via a factory method.

class User private constructor(val name: String) {
companion object {
fun newUser(name: String): User = User(name)
}
}

fun main() {
val user = User.newUser("Alice")
println("New user: ${user.name}")
}

Here, the the User class has a private constructor, and the companion object provides a factory method newUser to create instances. This design keeps the instantiation logic neatly inside the class.

Advanced Companion Object Features

Named Companion Objects

You can give your companion object a custom name if needed:

class Config {
companion object Settings {
const val MAX_CONNECTIONS = 10
fun displaySettings() {
println("Max connections: $MAX_CONNECTIONS")
}
}
}

fun main() {
println(Config.MAX_CONNECTIONS)
Config.Settings.displaySettings()
}

Implementing Interfaces

Companion objects can also implement interfaces, which allows you to define contract-based behaviours at the class level.

interface Logger {
fun log(message: String)
}

class Service {
companion object : Logger {
override fun log(message: String) {
println("Log: $message")
}
}
}

fun main() {
Service.log("Service started")
}

By implementing the Logger interface, the companion object of Service can be used wherever a Logger is required.

Using @JvmStatic for Java Interoperability

While Kotlin doesn’t have static methods, you can expose companion object members as static when calling from Java by using the @JvmStatic annotation:

class Utility {
companion object {
@JvmStatic
fun performAction() {
println("Action performed")
}
}
}

In Java, you can call this method directly:

Utility.performAction();

This interop feature makes companion objects a powerful tool when working in mixed-language projects.

Companion Objects vs. Regular Objects

Companion Objects:

  • Companion objects are created along with classes. They are initialised with the classes.
  • Companion Objects are used for static properties like accessing a variable or a function without initialising the class
  • We do need to define a name for the companion objects
  • Companion Objects are associated with the class. So they can not be accessed directly

Objects:

  • Objects are initialised lazily
  • Objects are used for Singleton purposes.
  • We need to define names for objects
  • Objects can be called directly by their name

If you want to learn more about Companion Objects. Here is a video for you:

Conclusion

Companion objects in Kotlin provide an elegant solution to many common programming needs — from defining constants and utility functions to implementing factory methods and interfaces. By grouping related functionality directly within your classes, you keep your code clean, modular, and highly maintainable.

--

--

Hitesh Kohli
Hitesh Kohli

Written by Hitesh Kohli

Hi, my name is Hitesh Kohli, I work at Geeks for Geeks as an Android developer. I love messing around with apps and games.

No responses yet