Companion object w Kotlin: co to jest, składnia i zastosowanie

Autor: IT Sectr Opublikowano: 2026-06-21 Czas czytania: 9 min

companion object — mechanizm języka Kotlin, zastępujący słowo kluczowe static z Javy do deklarowania statycznych członków klasy. W Kotlin nie ma wbudowanego static — zamiast tego używa się deklaracji object z modyfikatorem companion wewnątrz klasy. Według JetBrains, 2025, companion object pozwala wywoływać metody i właściwości przez nazwę klasy, co czyni je pełnym odpowiednikiem statycznych członków w ekosystemie Javy.

Najważniejsze

  • companion object — to deklaracja object wewnątrz klasy ze słowem kluczowym companion, zastępująca Java static
  • Statyczne członki są dostępne przez nazwę klasy bez tworzenia instancji: ClassName.method()
  • Nazwany companion object pozwala nadać nazwę obiektowi dla bardziej czytelnego kodu
  • Interfejsy w Kotlin mogą również zawierać companion object z implementacją metod
  • @JvmStatic — adnotacja do eksportu metod companion object jako prawdziwych static-metod w Javie

Czym jest companion object w Kotlin?

companion object — to specjalna odmiana object declaration w języku Kotlin, która jest oznaczana słowem kluczowym companion. Pozwala ona deklarować członki należące do klasy, a nie do jej instancji — czyli statyczne członki w terminologii Javy. W przeciwieństwie do Javy, gdzie static jest modyfikatorem dla pojedynczych pól i metod, w Kotlin statyczne członki są grupowane wewnątrz jednego obiektu-towarzysza.

Każda klasa w Kotlin może zawierać dokładnie jeden companion object. Członki tego obiektu są dostępne przez nazwę klasy bez tworzenia instancji: MyClass.method(). Jednocześnie z perspektywy kodu bajtowego companion object jest kompilowany do oddzielnej wewnętrznej klasy, a jego metody stają się statycznymi metodami zewnętrznej klasy przy użyciu adnotacji @JvmStatic.

Według Google I/O 2024, companion object stał się głównym wzorcem dla metod fabrycznych, stałych i funkcji pomocniczych we współczesnych aplikacjach Android w Kotlin. Deweloperzy wybierają go zamiast klas narzędziowych z funkcjami pakietowymi, ponieważ companion object zachowuje logiczne powiązanie z klasą-właścicielem.

Używaj companion object do grupowania statycznego kontekstu — stałych, fabryk, metod pomocniczych, które logicznie odnoszą się do klasy, ale nie wymagają instancji.

Składnia companion object: deklaracja i dostęp

Podstawowa składnia companion object jest prosta: słowo kluczowe companion stawiamy przed deklaracją object wewnątrz klasy. Jeśli nazwa nie jest podana, obiekt otrzymuje nazwę Companion, do którego można odwoływać się jawnie lub niejawnie.

kotlin
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 }
}

// Dostęp przez nazwę klasy
val table = User.TABLE_NAME
val user = User.create("Alice")

W powyższym przykładzie TABLE_NAME i create() są dostępne przez User.TABLE_NAME i User.create(). Zwróć uwagę na modyfikator const dla prymitywnych stałych — gwarantuje on wbudowanie wartości na etapie kompilacji, analogicznie do Java static final dla primitives i String.

Niejawny i jawny dostęp przez Companion

Jeśli companion object nie ma nazwy, można odwołać się do niego przez automatyczną nazwę Companion: User.Companion.TABLE_NAME. W praktyce jest to rzadko potrzebne, ale przydatne przy wywołaniach z kodu Javy lub przy użyciu refleksji.

kotlin
// Oba wywołania są równoważne
User.create("Bob")
User.Companion.create("Bob")

// Pobranie referencji do companion object
val companion: User.Companion = User

Nazwany companion object i cechy szczególne

companion object może mieć nazwę, co poprawia czytelność kodu i pozwala odwoływać się do niego po zrozumiałej nazwie. Factory — to najczęstsza nazwa dla companion object używanego jako fabryka.

kotlin
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")
    }
}

// Dostęp przez nazwę Factory
val response = HttpResponse.Factory.ok("data")

Nazwany companion object pomaga dokumentować przeznaczenie statycznych członków. Podczas refaktoryzacji nazwa czyni kod samodokumentującym się — deweloper od razu widzi, że Factory tworzy instancje HttpResponse.

Ograniczenie: tylko jeden companion object na klasę

Klasa może zawierać tylko jeden companion object. To zasadnicza różnica w stosunku do Javy, gdzie można zadeklarować dowolną liczbę statycznych pól i metod bez grupowania. Jeśli potrzebujesz kilku logicznych grup statycznych członków, używaj zagnieżdżonych object declarations bez companion.

Według danych oficjalnej dokumentacji Kotlin (Kotlin Docs, 2025), ograniczenie do jednego companion object wynika z projektu języka: statyczne członki powinny być ściśle powiązane z klasą, a jeden obiekt-towarzysz zapewnia wyraźną granicę tego powiązania. Jeśli statycznych członków jest zbyt wiele — to sygnał do refaktoryzacji klasy.

Companion object w interfejsach

W Kotlin interfejsy również mogą zawierać companion object. Pozwala to definiować statyczne metody i stałe bezpośrednio wewnątrz interfejsu, co jest niemożliwe w Javie. Takie podejście jest często używane do deklarowania stałych związanych z interfejsem lub metod fabrycznych.

kotlin
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)
    }
}

W tym przykładzie BASE_URL, TIMEOUT_MS i create() należą do interfejsu ApiService, a nie do jego implementacji. Jest to wygodne: wszystkie stałe i logika fabryczna do tworzenia instancji serwisu API znajdują się w jednym miejscu — wewnątrz samego interfejsu.

Implementacje interfejsu nie dziedziczą członków companion object — są one wywoływane tylko przez nazwę interfejsu: ApiService.BASE_URL.

@JvmStatic i @JvmField: zgodność z Javą

Przy wywoływaniu metod companion object z kodu Javy są one domyślnie dostępne jako metody zagnieżdżonej klasy Companion, a nie jako statyczne metody zewnętrznej klasy. Aby wyeksportować je jako prawdziwe static metody i pola dla Javy, użyj adnotacji @JvmStatic dla metod i @JvmField dla pól.

AdnotacjaZastosowanieWynik w Javie
@JvmStaticMetody companion objectStatyczna metoda: ClassName.method()
@JvmFieldPola companion objectStatyczne pole: ClassName.field
constPrymitywy i StringInline-stała: kompilator podstawia wartość
bez adnotacjiMetody/pola domyślnieCompanion.method() / Companion.field
kotlin
class MathUtils {
    companion object {
        const val PI = 3.14159

        @JvmStatic
        fun square(x: Int): Int = x * x

        @JvmField
        val TAG: String = "MathUtils"
    }
}

// Wywołane w Javie jako MathUtils.square(5), MathUtils.TAG

Używanie @JvmStatic jest zalecane dla wszystkich publicznych metod companion object, które mają być dostępne z kodu Javy. const stosuje się tylko do typów prymitywnych i String — dla pozostałych typów używaj @JvmField.

Praktyczne przykłady użycia companion object

W rzeczywistych projektach companion object jest używany do kilku standardowych scenariuszy. Metody fabryczne — to najczęstszy wzorzec: zamiast wielu konstruktorów z różnymi sygnaturami stosuje się nazwane metody fabryczne w companion object.

kotlin
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 w NetworkResult dostarcza metodę fabryczną loading(), która tworzy instancję Loading z poprawnym typem generic. Bez tej metody trzeba by tworzyć instancję bezpośrednio przez Loading(), co ujawnia wewnętrzną implementację.

Stałe i tagi do logowania

Często companion object jest używany do przechowywania stałych specyficznych dla klasy. Stałe zadeklarowane z const val są wbudowywane na etapie kompilacji, co daje zerowy narzut w czasie wykonania.

kotlin
class UserRepository {
    companion object {
        private const val TAG = "UserRepository"
        private const val CACHE_SIZE = 100
        private const val DEFAULT_PAGE_SIZE = 20
    }
}

Często zadawane pytania

Czym różni się companion object od zwykłego object w Kotlin?

ordinary object — to pełnoprawny singleton, istniejący niezależnie od klasy. companion object — to object wewnątrz klasy, którego członki są wywoływane przez nazwę zewnętrznej klasy. W kodzie bajtowym companion object staje się statyczną klasą zagnieżdżoną, a zwykły object — autonomiczną klasą-singletonem.

Czy można dziedziczyć companion object?

Nie, companion object nie jest dziedziczony przez podklasy. Jeśli klasa B dziedziczy po klasie A, to B.method() nie wywoła metody z companion object klasy A — należy odwoływać się przez A.method(). Odpowiada to zachowaniu statycznych metod w Javie.

Jak wywołać companion object z kodu Javy?

Domyślnie — przez ClassName.Companion.method(). Aby wywoływać jako statyczną metodę, dodaj @JvmStatic do metody companion object. Dla pól używaj @JvmField lub zadeklaruj je z const val dla prymitywów.

Dlaczego w Kotlin nie ma słowa kluczowego static?

Twórcy Kotlina postanowili zrezygnować z static na rzecz companion object dla jednolitej pracy z obiektami. static w Javie narusza zasady OOP, ponieważ statyczne metody nie są powiązane z instancją. companion object — to obiekt pierwszej klasy, który można przekazywać, rozszerzać funkcjami-rozszerzeniami i implementować interfejsy.

Czy companion object wpływa na wydajność?

Przy użyciu const val dla prymitywów i String — zerowy narzut, wartość jest wbudowywana w kod bajtowy. Dla metod narzut nie występuje, jeśli metoda nie jest inline. W większości przypadków companion object nie tworzy mierzalnego wpływu na wydajność. Używaj @JvmStatic tylko dla publicznego API wywoływanego z Javy.

Podsumowanie

  • companion object — mechanizm Kotlin do deklarowania statycznych członków klasy, zastępujący Java static
  • Jeden companion object na klasę — grupuje wszystkie statyczne elementy w jednym obiekcie-towarzyszu
  • Dostęp przez nazwę klasy: ClassName.method() lub ClassName.Companion.method()
  • @JvmStatic i @JvmField eksportują członki jako prawdziwe statyczne metody i pola dla Javy
  • const val dla prymitywów i String — wbudowuje wartość na etapie kompilacji bez narzutu
  • Interfejsy również obsługują companion object dla stałych i metod fabrycznych
  • Nazwany companion object poprawia czytelność kodu i samodokumentuje przeznaczenie statycznych członków

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również