skip to content

companion object

A companion object holds members you call on the class name, which is Kotlin's replacement for statics — but they are instance members of a real object. @JvmStatic matters when Java code needs to call them without going through Companion.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What is a companion object in Kotlin, and how do you call its members?

level: juniorimportance: must knowfreq 80%

answer

  1. No 'static' in Kotlin -> companion object
  2. Called on the class name: User.create()
  3. One companion per class
  4. Accessible as MyClass.Companion (real object)
  5. const val for inlined constants

basics

~10 s

It is a special object declared inside a class with the 'companion object' keywords. Its properties and functions can be called using the class name directly, without creating an instance.

solid answer

~40 s

A companion object is an object declaration nested in a class, written with 'companion object { ... }'. There is exactly one per class. Its members (functions, properties, constants) are accessed via the enclosing class name, e.g. MyClass.create(), without instantiating MyClass. It is Kotlin's idiomatic replacement for Java 'static' members since Kotlin has no 'static' keyword. The companion is itself a real singleton object instance, accessible as MyClass.Companion, so it can implement interfaces and extend classes. Members are NOT JVM statics by default — to expose true statics to Java callers you add @JvmStatic. Constants meant to be inlined use 'const val' inside the companion.

code

kotlin · 9 lines
kotlin
class Circle private constructor(val radius: Double) {
    companion object {
        const val PI = 3.14159
        fun ofDiameter(d: Double) = Circle(d / 2)
    }
}

val c = Circle.ofDiameter(10.0)
println(Circle.PI)

go deeper

for a junior

Knows the syntax and that members are called on the class name without an instance.

for a middle

Adds that it is a real singleton (MyClass.Companion) and replaces Java static.

for a senior

Notes JVM-static distinction, const val, and access to private class members.

for a principal

Frames companion vs top-level declarations as an API-surface and binary-compatibility choice.

## What it is Kotlin has **no `static` keyword**. To attach members to a class (not to its instances), you put them inside a **companion object** — a single object declaration nested in the class with the `companion object` keyword. ```kotlin class User(val name: String) { companion object { val DEFAULT_NAME = "Anonymous" fun create(name: String): User = User(name) } } val u = User.create("Ann") // called on the class name println(User.DEFAULT_NAME) // no instance needed ``` ## Key facts - **One per class.** A class may declare at most one companion object. - **Called on the class name.** `User.create(...)` looks like a Java static call, but mechanically it is a method call on a hidden singleton instance. - **It is a real object.** The companion is accessible explicitly as `User.Companion`. Because it is an object, it can **implement interfaces** and **extend a superclass** — something Java statics cannot do. - **Not JVM static by default.** From Java the member is reached as `User.Companion.create(...)`. Add `@JvmStatic` to a member to also generate a true static so Java can write `User.create(...)`. - **Constants:** use `const val NAME = "..."` for compile-time constants of primitive/String type; they are inlined at call sites. - **Access to private members.** Companion code can read the enclosing class's `private` members and vice versa, which is why it is the standard place for factory functions. ## Terms - **object declaration**: `object Foo { ... }` defines a singleton; a companion is an object tied to a class. - **singleton**: exactly one instance exists for the whole program. Use the companion for class-level helpers, named constants, and factory functions.

  • Does Kotlin have a 'static' keyword?
    No. Class-level members go in a companion object (or a top-level declaration in a file).
  • Can you have two companion objects in one class?
    No. At most one companion object per class, though you can have additional named (non-companion) nested objects.

Like a Java 'static' block, but it is actually a real singleton object riding inside the class.

saying these in an interview costs you the question

  • Claiming Kotlin has a 'static' keyword
  • Saying you must create an instance to call companion members
  • Thinking a class can have multiple companion objects
  • Believing companion members are automatically JVM statics for Java

context

open as a page

What is a named companion object, when would you name it, and how does naming affect call syntax from Kotlin and Java?

level: middleimportance: should knowfreq 45%

basics

~20 s

You can give the companion a name, like 'companion object Factory'. From Kotlin you still call members on the class name. The name lets you reference the companion explicitly and is used by Java callers.

open as a page

How does a Kotlin companion object differ from Java static members at the bytecode/runtime level?

level: middleimportance: should knowfreq 65%

basics

~10 s

Companion members are not real static methods by default. They live on a hidden singleton instance, so from Java you call them through a generated 'Companion' field. Adding @JvmStatic makes them true statics.

open as a page

Explain @JvmStatic on companion members: what it generates, its interaction with @JvmField/const, and the interop trade-offs.

level: seniorimportance: should knowfreq 40%

basics

~10 s

@JvmStatic tells the compiler to also emit a real static method or accessor on the outer class, so Java can call MyClass.foo() instead of MyClass.Companion.foo(). The companion still exists underneath.

open as a page

When is a companion object initialized, and what concurrency/initialization pitfalls arise from putting mutable state in it?

level: seniorimportance: nice to knowfreq 28%

basics

~20 s

The companion is created once, lazily, the first time the class or a companion member is used. Because it is shared by everything, any mutable state in it is global and must be made thread-safe.

open as a page