companion object — mechanismus jazyka Kotlin, který nahrazuje klíčové slovo static z Javy pro deklaraci statických členů třídy. V Kotlinu není vestavěný static — místo toho se používá deklarace object s modifikátorem companion uvnitř třídy. Podle JetBrains, 2025, companion object umožňuje volat metody a vlastnosti přes název třídy, což je činí plnohodnotnou obdobou statických členů v ekosystému Javy.
Hlavní body
companion object — je speciální druh object declaration v jazyce Kotlin, který je označen klíčovým slovem companion. Umožňuje deklarovat členy, které patří třídě, nikoli jejím instancím — tedy statické členy v terminologii Javy. Na rozdíl od Javy, kde static je modifikátor pro jednotlivá pole a metody, v Kotlinu jsou statické členy seskupeny uvnitř jednoho objektu-průvodce.
Jakákoli třída v Kotlinu může obsahovat právě jeden companion object. Členy tohoto objektu jsou přístupné přes název třídy bez vytváření instance: MyClass.method(). Z hlediska bajtového kódu je companion object kompilován do samostatné vnitřní třídy a jeho metody se stávají statickými metodami vnější třídy při použití anotace @JvmStatic.
Podle Google I/O 2024 se companion object stal hlavním vzorem pro tovární metody, konstanty a pomocné funkce v moderních Android aplikacích v Kotlinu. Vývojáři jej volí místo pomocných tříd s funkcemi balíčku, protože companion object zachovává logické spojení s vlastnickou třídou.
Používejte companion object pro seskupování statického kontextu — konstanty, továrny, pomocné metody, které logicky patří ke třídě, ale nevyžadují instanci.
Základní syntaxe companion object je jednoduchá: klíčové slovo companion se umístí před deklaraci object uvnitř třídy. Pokud není uveden název, objekt získá název Companion, na který lze odkazovat explicitně nebo implicitně.
class User {
companion object {
const val TABLE_NAME = "users"
fun create(name: String): User {
return User(name)
}
}
val name: String
constructor(name: String) { this.name = name }
}
// Přístup přes název třídy
val table = User.TABLE_NAME
val user = User.create("Alice")
V uvedeném příkladu jsou TABLE_NAME a create() přístupné přes User.TABLE_NAME a User.create(). Všimněte si modifikátoru const pro primitivní konstanty — zaručuje vložení hodnoty ve fázi kompilace, analogicky k Java static final pro primitiva a String.
Pokud companion object nemá název, lze k němu přistupovat přes automatický název Companion: User.Companion.TABLE_NAME. V praxi je to zřídka potřeba, ale užitečné při volání z Java kódu nebo při použití reflexe.
// Oba dotazy jsou ekvivalentní
User.create("Bob")
User.Companion.create("Bob")
// Získání reference na companion object
val companion: User.Companion = User
companion object může mít název, což zlepšuje čitelnost kódu a umožňuje na něj odkazovat srozumitelným názvem. Factory — nejběžnější název pro companion object používaný jako továrna.
class HttpResponse {
companion object Factory {
fun ok(body: String): HttpResponse = HttpResponse(200, body)
fun notFound(): HttpResponse = HttpResponse(404, "Not Found")
fun serverError(): HttpResponse = HttpResponse(500, "Internal Error")
}
}
// Přístup přes název Factory
val response = HttpResponse.Factory.ok("data")
Pojmenovaný companion object pomáhá dokumentovat účel statických členů. Při refaktorování název činí kód samodokumentujícím — vývojář okamžitě vidí, že Factory vytváří instance HttpResponse.
Třída může obsahovat pouze jeden companion object. To je zásadní rozdíl oproti Javě, kde lze deklarovat libovolný počet statických polí a metod bez seskupování. Pokud je potřeba několik logických skupin statických členů, použijte vnořené deklarace object bez companion.
Podle oficiální dokumentace Kotlinu (Kotlin Docs, 2025) je omezení na jeden companion object motivováno návrhem jazyka: statické členy by měly být úzce spojeny s třídou a jeden objekt-průvodce poskytuje jasnou hranici tohoto spojení. Pokud je statických členů příliš mnoho — je to signál k refaktorování třídy.
V Kotlinu mohou také rozhraní obsahovat companion object. To umožňuje definovat statické metody a konstanty přímo uvnitř rozhraní, což není možné v Javě. Tento přístup se často používá pro deklaraci konstant souvisejících s rozhraním nebo továrních metod.
interface ApiService {
companion object {
const val BASE_URL = "https://api.example.com"
const val TIMEOUT_MS = 5000
fun create(client: OkHttpClient): ApiService =
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.build()
.create(ApiService::class.java)
}
}
V tomto příkladu BASE_URL, TIMEOUT_MS a create() patří rozhraní ApiService, nikoli jeho implementacím. To je pohodlné: všechny konstanty a tovární logika pro vytvoření instance API služby jsou na jednom místě — uvnitř samotného rozhraní.
Implementace rozhraní nedědí členy companion object — jsou volány pouze přes název rozhraní: ApiService.BASE_URL.
Při volání metod companion object z Java kódu jsou standardně dostupné jako metody vnořené třídy Companion, nikoli jako statické metody vnější třídy. Chcete-li je exportovat jako skutečné static metody a pole pro Javu, použijte anotaci @JvmStatic pro metody a @JvmField pro pole.
| Anotace | Použití | Výsledek v Javě |
|---|---|---|
| @JvmStatic | Metody companion object | Statická metoda: ClassName.method() |
| @JvmField | Pole companion object | Statické pole: ClassName.field |
| const | Primitiva a String | Inline konstanta: kompilátor dosadí hodnotu |
| bez anotace | Výchozí metody/pole | Companion.method() / Companion.field |
class MathUtils {
companion object {
const val PI = 3.14159
@JvmStatic
fun square(x: Int): Int = x * x
@JvmField
val TAG: String = "MathUtils"
}
}
// Voláno v Javě jako MathUtils.square(5), MathUtils.TAG
Použití @JvmStatic je doporučeno pro všechny veřejné metody companion object, které by měly být přístupné z Java kódu. const se aplikuje pouze na primitivní typy a String — pro ostatní typy použijte @JvmField.
V reálných projektech se companion object používá pro několik standardních scénářů. Tovární metody — nejběžnější vzor: místo mnoha konstruktorů s různými signaturami se používají pojmenované tovární metody v companion object.
sealed class NetworkResult<out T> {
data class Success<out T>(val data: T) : NetworkResult<T>()
data class Error(val message: String) : NetworkResult<Nothing>()
companion object {
fun loading<T>(): NetworkResult<T> =
Loading()
}
}
private class Loading<T> : NetworkResult<T>()
companion object v NetworkResult poskytuje tovární metodu loading(), která vytváří instanci Loading se správným generickým typem. Bez této metody byste museli vytvářet instanci přímo přes Loading(), což odhaluje interní implementaci.
Často se companion object používá pro ukládání konstant specifických pro třídu. Konstanty deklarované s const val jsou vloženy ve fázi kompilace, což poskytuje nulovou režii za běhu.
class UserRepository {
companion object {
private const val TAG = "UserRepository"
private const val CACHE_SIZE = 100
private const val DEFAULT_PAGE_SIZE = 20
}
}
Často kladené otázky
ordinary object — je plnohodnotný singleton existující nezávisle na třídě. companion object — je object uvnitř třídy, jehož členy jsou volány přes název vnější třídy. V bajtovém kódu se companion object stává statickou vnořenou třídou a běžný object — autonomní singleton třídou.
Ne, companion object není děděn podtřídami. Pokud třída B dědí třídu A, B.method() nevyvolá metodu z companion object třídy A — je třeba přistupovat přes A.method(). To odpovídá chování statických metod v Javě.
Výchozí — přes ClassName.Companion.method(). Chcete-li volat jako statickou metodu, přidejte @JvmStatic k metodě companion object. Pro pole použijte @JvmField nebo je deklarujte s const val pro primitiva.
Vývojáři Kotlinu se rozhodli opustit static ve prospěch companion object pro jednotnou práci s objekty. static v Javě porušuje principy OOP, protože statické metody nejsou vázány na instanci. companion object — je objekt první třídy, který lze předávat, rozšiřovat rozšiřujícími funkcemi a implementovat rozhraní.
Při použití const val pro primitiva a String — nulová režie, hodnota je vložena do bajtového kódu. Pro metody není režie, pokud metoda není inline. Ve většině případů companion object nemá měřitelný dopad na výkon. Používejte @JvmStatic pouze pro veřejné API volané z Javy.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také