What is a named companion object, when would you name it, and how does naming affect call syntax from Kotlin and Java?
answer
- Default implicit name is 'Companion'
- companion object Name { } to rename
- MyClass.member() works regardless of name
- Name appears in Java interop and as extension receiver
- Still only ONE companion per class
basics
~20 sYou 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.
solid answer
~40 sBy default a companion's implicit name is 'Companion'. You can rename it: 'companion object Named { ... }'. From Kotlin you usually still call MyClass.member() — the name is optional sugar — but you may also write MyClass.Named.member() or pass MyClass.Named as a value. The name matters most for (1) readability/semantics (e.g. naming it 'Factory'), (2) Java interop, where the nested class and field take that name so Java calls MyClass.Named.member(), and (3) declaring companion-object extensions: 'fun MyClass.Named.ext()' or 'fun MyClass.Companion.ext()'. There is still only one companion per class; naming does not let you have several. A common use is exposing the companion as a receiver so libraries can hang extension functions off it.
code
kotlin · 13 linesclass Color(val rgb: Int) {
companion object Factory {
fun fromHex(hex: String) = Color(hex.removePrefix("#").toInt(16))
}
}
// All valid from Kotlin:
Color.fromHex("#FF0000")
Color.Factory.fromHex("#FF0000")
// Extension hung off the named companion:
fun Color.Factory.black() = Color(0)
Color.black()go deeper
Knows the companion can be given a name after 'object'.
Explains default 'Companion' name, that class-name calls still work, and Java interop impact.
Uses companion extensions as a receiver-based extensibility mechanism and knows the one-per-class rule.
Designs library APIs around companion-extension points and considers interop/naming for public surfaces.
## Default name If you do not name it, the companion is implicitly called **`Companion`**: ```kotlin class Json { companion object { fun parse(s: String) = s } } Json.parse("{}") // call on class name Json.Companion.parse("{}") // explicit default name ``` ## Naming it Give the companion an explicit name after the `object` keyword: ```kotlin class Json { companion object Parser { fun parse(s: String) = s } } Json.parse("{}") // still works (companion-on-class-name sugar) Json.Parser.parse("{}") // explicit named reference ``` ## Where the name shows up - **Kotlin call sites:** `MyClass.member()` always works regardless of name. You only need the name when referring to the companion **as a value/receiver**. - **Java interop:** the generated nested class and static field use the chosen name, so Java writes `Json.Parser.parse("{}")` (or `Json.Companion...` if unnamed). `@JvmStatic` still lets Java call `Json.parse(...)` directly. - **Extension functions on the companion:** to add `Json.parseFile(...)` from another module, declare an extension on the companion receiver: ```kotlin fun Json.Parser.parseFile(path: String): String = parse(readText(path)) // or, if unnamed: fun Json.Companion.parseFile(...) { ... } ``` This pattern lets third-party libraries 'attach' factory-like helpers to a type's companion. **You cannot declare such an extension unless the class actually has a companion** (named or default). ## Rules and limits - Still **only one companion per class**; the name does not allow multiples. - Naming is mostly about **clarity** and **interop ergonomics**; it changes no runtime semantics for Kotlin call sites. - You can additionally have ordinary (non-companion) **named nested objects**, but those are not reachable via the bare class-name sugar. ## When to name Name it when the role is meaningful (`Factory`, `Parser`, `Serializer`), when Java/other consumers benefit from a descriptive nested type, or when you (or library authors) want a clear receiver for companion extensions.
- If you name the companion 'Factory', can you still call MyClass.member()?Yes. The bare class-name call always works; the name is only needed when referencing the companion explicitly.
- Why might you declare an extension on MyClass.Companion?To let another module add factory-style helpers callable as MyClass.helper(), without modifying the original class.
saying these in an interview costs you the question
- Thinking naming the companion allows multiple companions
- Believing MyClass.member() stops working once you name the companion
- Not realizing the name affects Java interop call syntax
- Confusing a named companion with a separate named nested object