You have a Kotlin class with a companion object containing a function create(). How do you call that function from Java, and why isn't the call simply Foo.create()?
answer
- Default: Foo.Companion.create()
- Companion = static field + nested class
- @JvmStatic adds a real static method
- Foo.create() fails without @JvmStatic
- Named companion renames Companion
basics
~10 sFrom Java you call Foo.Companion.create(). Kotlin puts companion members on a nested object named Companion, so Java must go through that object rather than calling the method straight on the class.
solid answer
~40 sA Kotlin companion object compiles to a real nested class/instance exposed to Java as a static field named Companion on the outer class. So `companion object { fun create() = ... }` is reached from Java as `Foo.Companion.create()`. Java does NOT see `Foo.create()` by default, because Kotlin's companion is an object instance, not a set of Java static methods. To make `Foo.create()` work, annotate the companion function with `@JvmStatic`, which generates a genuine static method on `Foo` (the Companion delegate stays too). For properties, `@JvmStatic` on the val/getter or `@JvmField`/`const` changes the surfaced shape. Without those annotations, the Companion indirection is mandatory from Java.
code
kotlin · 10 linesclass Foo {
companion object {
@JvmStatic fun create(): Foo = Foo()
fun build(): Foo = Foo()
}
}
// Java:
// Foo.create(); // OK (@JvmStatic)
// Foo.Companion.build(); // OK (default path)
// Foo.build(); // does NOT compilego deeper
Knows the default Java path is Foo.Companion.create() and that @JvmStatic enables Foo.create().
Explains the generated Foo$Companion class + static Companion field and that @JvmStatic adds a delegate without removing the field.
Discusses API-design implications: annotate factory/constants for clean Java APIs, and the named-companion option for clarity.
Sets a team convention for which companion members get @JvmStatic to keep a stable, idiomatic Java surface across a multi-language codebase.
## What a companion object is In Kotlin a class can have ONE `companion object` — a singleton tied to the class, used for factory functions, constants, and other 'class-level' members. Kotlin lets you write `Foo.create()` from Kotlin because the compiler resolves the companion implicitly. ## How it looks to Java The companion compiles to a real nested type. The JVM sees: - a nested class `Foo$Companion` - a `public static final Foo$Companion Companion` field on `Foo` So from Java the default access path is: ```java Foo.Companion.create(); ``` Java can't write `Foo.create()` because there is no static `create` method on `Foo` — the method lives on the `Companion` instance. ## Making it a true static: @JvmStatic Annotating the companion function makes the compiler ALSO emit a static method on the outer class: ```kotlin class Foo { companion object { @JvmStatic fun create(): Foo = Foo() fun build(): Foo = Foo() // no annotation } } ``` From Java: ```java Foo.create(); // works — @JvmStatic Foo.Companion.create(); // also still works Foo.Companion.build(); // only path for build() Foo.build(); // COMPILE ERROR ``` ## Key terms - **companion object**: the per-class singleton holding class-level members. - **`@JvmStatic`**: annotation that tells the Kotlin compiler to additionally generate a JVM `static` method/accessor, so Java can call it without the `Companion` hop. - **`Companion`**: the auto-generated name of the static field/nested class (you can rename it: `companion object Named { }` → `Foo.Named`). From Kotlin nothing changes — `Foo.create()` works either way. The annotations only affect the Java-facing surface.
- Can you change the 'Companion' name Java sees?Yes — give the companion a name: `companion object Factory { }` makes Java write `Foo.Factory.create()`.
- Does @JvmStatic remove the Companion field?No. The Companion field/instance still exists; @JvmStatic adds a static delegate in addition, so both paths compile.
The companion is like a receptionist named 'Companion' standing at the company's front desk — Java must ask the receptionist; @JvmStatic gives the company its own direct phone line.
saying these in an interview costs you the question
- Claiming Java can call Foo.create() with no annotation
- Thinking companion members are Java statics by default
- Confusing companion object with a Java static nested class with static methods
- Saying @JvmStatic is required for Kotlin callers too