Companion object in Kotlin: wat is het, syntaxis en toepassing

Auteur: IT Sectr Gepubliceerd: 2026-06-21 Leestijd: 9 min

companion object — het mechanisme van Kotlin dat het sleutelwoord static uit Java vervangt voor het declareren van statische leden van een klasse. Kotlin heeft geen ingebouwde static — in plaats daarvan wordt een object-declaratie met de modificator companion binnen de klasse gebruikt. Volgens JetBrains, 2025 maakt companion object het mogelijk om methoden en eigenschappen via de klassenaam aan te roepen, wat ze de volledige equivalent maakt van statische leden in het Java-ecosysteem.

Belangrijkste punten

  • companion object — een object-declaratie binnen de klasse met het sleutelwoord companion, ter vervanging van Java static
  • Statische leden zijn toegankelijk via de klassenaam zonder een instantie te maken: ClassName.method()
  • Benoemde companion object maakt het mogelijk een naam aan het object te geven voor beter leesbare code
  • Interfaces in Kotlin kunnen ook een companion object bevatten met methode-implementaties
  • @JvmStatic — annotatie om companion object-methoden als echte static-methoden in Java te exporteren

Wat is companion object in Kotlin?

companion object — is een speciale variant van object declaration in Kotlin, gemarkeerd met het sleutelwoord companion. Het maakt het mogelijk leden te declareren die bij de klasse horen, niet bij de instanties — dus statische leden in Java-terminologie. In tegenstelling tot Java, waar static een modificator is voor individuele velden en methoden, worden in Kotlin statische leden gegroepeerd binnen één companion-object.

Elke klasse in Kotlin kan precies één companion object bevatten. Leden van dit object zijn toegankelijk via de klassenaam zonder een instantie te maken: MyClass.method(). Vanuit bytecode-perspectief wordt companion object gecompileerd tot een aparte innerlijke klasse, en de methoden worden statische methoden van de buitenste klasse bij gebruik van de @JvmStatic-annotatie.

Volgens Google I/O 2024 is companion object het belangrijkste patroon geworden voor fabrieksmethoden, constanten en hulpfuncties in moderne Android-applicaties in Kotlin. Ontwikkelaars kiezen het boven hulpklassen met pakketfuncties, omdat companion object de logische band met de eigenaar-klasse behoudt.

Gebruik companion object voor het groeperen van statische context — constanten, fabrieken, hulpmethoden die logisch bij de klasse horen maar geen instantie vereisen.

Syntaxis van companion object: declaratie en toegang

De basissyntaxis van companion object is eenvoudig: het sleutelwoord companion wordt voor de object-declaratie binnen de klasse geplaatst. Als er geen naam wordt opgegeven, krijgt het object de naam Companion, waarnaar expliciet of impliciet kan worden verwezen.

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

// Toegang via klassenaam
val table = User.TABLE_NAME
val user = User.create("Alice")

In bovenstaand voorbeeld zijn TABLE_NAME en create() toegankelijk via User.TABLE_NAME en User.create(). Let op de modificator const voor primitieve constanten — deze garandeert het inlinen van de waarde tijdens compilatie, analoog aan Java static final voor primitives en String.

Impliciete en expliciete toegang via Companion

Als companion object geen naam heeft, kan het worden benaderd via de automatische naam Companion: User.Companion.TABLE_NAME. In de praktijk is dit zelden nodig, maar handig bij aanroep vanuit Java-code of bij gebruik van reflectie.

kotlin
// Beide aanroepen zijn equivalent
User.create("Bob")
User.Companion.create("Bob")

// Referentie naar companion object verkrijgen
val companion: User.Companion = User

Benoemde companion object en kenmerken

companion object kan een naam hebben, wat de leesbaarheid van de code verbetert en het mogelijk maakt het object met een begrijpelijke naam aan te spreken. Factory — de meest voorkomende naam voor een companion object dat als fabriek wordt gebruikt.

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

// Toegang via Factory-naam
val response = HttpResponse.Factory.ok("data")

Een benoemde companion object helpt bij het documenteren van het doel van statische leden. Bij refactoring maakt de naam de code zelfdocumenterend — de ontwikkelaar ziet direct dat Factory instanties van HttpResponse maakt.

Beperking: precies één companion object per klasse

Een klasse kan slechts één companion object bevatten. Dit is een fundamenteel verschil met Java, waar elk aantal statische velden en methoden zonder groepering kan worden gedeclareerd. Als meerdere logische groepen statische leden nodig zijn, gebruik dan geneste object-declaraties zonder companion.

Volgens de officiële Kotlin-documentatie (Kotlin Docs, 2025) is de beperking tot één companion object gemotiveerd door het taalontwerp: statische leden moeten nauw verbonden zijn met de klasse, en één companion-object zorgt voor een duidelijke grens van deze verbinding. Als er te veel statische leden zijn — is dat een signaal voor refactoring van de klasse.

Companion object in interfaces

In Kotlin kunnen ook interfaces een companion object bevatten. Dit maakt het mogelijk om statische methoden en constanten direct binnen de interface te definiëren, wat niet mogelijk is in Java. Deze benadering wordt vaak gebruikt voor het declareren van constanten die aan de interface zijn gekoppeld, of fabrieksmethoden.

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

In dit voorbeeld behoren BASE_URL, TIMEOUT_MS en create() tot de interface ApiService, niet tot de implementaties ervan. Dit is handig: alle constanten en fabriekslogica voor het maken van een API-service-instantie bevinden zich op één plek — binnen de interface zelf.

Implementaties van de interface erven de leden van companion object niet — ze worden alleen via de interfacenaam aangeroepen: ApiService.BASE_URL.

@JvmStatic en @JvmField: compatibiliteit met Java

Bij het aanroepen van companion object-methoden vanuit Java-code zijn ze standaard beschikbaar als methoden van de geneste klasse Companion, niet als statische methoden van de buitenste klasse. Om ze te exporteren als echte static-methoden en -velden voor Java, gebruik de annotatie @JvmStatic voor methoden en @JvmField voor velden.

AnnotatieToepassingResultaat in Java
@JvmStaticCompanion object-methodenStatische methode: ClassName.method()
@JvmFieldCompanion object-veldenStatisch veld: ClassName.field
constPrimitives en StringInline-constante: compiler substitueert waarde
geen annotatieStandaard methoden/veldenCompanion.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"
    }
}

// Aangeroepen in Java als MathUtils.square(5), MathUtils.TAG

Het gebruik van @JvmStatic wordt aanbevolen voor alle openbare methoden van companion object die toegankelijk moeten zijn vanuit Java-code. const wordt alleen toegepast op primitieve typen en String — voor andere typen gebruik @JvmField.

Praktische voorbeelden van het gebruik van companion object

In echte projecten wordt companion object gebruikt voor verschillende standaard scenario's. Fabrieksmethoden — het meest voorkomende patroon: in plaats van meerdere constructors met verschillende handtekeningen worden benoemde fabrieksmethoden in companion object gebruikt.

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 in NetworkResult biedt de fabrieksmethode loading() die een Loading-instantie maakt met het juiste generic-type. Zonder deze methode zou u de instantie direct via Loading() moeten maken, wat de interne implementatie blootlegt.

Constanten en tags voor logging

Vaak wordt companion object gebruikt voor het opslaan van klassenspecifieke constanten. Constanten gedeclareerd met const val worden tijdens compilatie geïnlined, wat nul overhead in runtime oplevert.

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

Veelgestelde vragen

Wat is het verschil tussen companion object en een gewoon object in Kotlin?

ordinary object — is een volwaardige singleton die onafhankelijk van de klasse bestaat. companion object — is een object binnen de klasse waarvan de leden worden aangeroepen via de naam van de buitenste klasse. In bytecode wordt companion object een statische geneste klasse, en een gewoon object wordt een autonome singleton-klasse.

Kan companion object worden overgeërfd?

Nee, companion object wordt niet overgeërfd door subklassen. Als klasse B overerft van klasse A, roept B.method() geen methode aan uit companion object van klasse A — u moet via A.method() benaderen. Dit komt overeen met het gedrag van statische methoden in Java.

Hoe roep ik companion object aan vanuit Java-code?

Standaard — via ClassName.Companion.method(). Om als statische methode aan te roepen, voeg @JvmStatic toe aan de companion object-methode. Voor velden gebruik @JvmField of declareer ze met const val voor primitieven.

Waarom heeft Kotlin geen static-sleutelwoord?

De ontwikkelaars van Kotlin hebben besloten static te laten vallen ten gunste van companion object voor uniform werken met objecten. static in Java schendt de OOP-principes omdat statische methoden niet aan een instantie zijn gebonden. companion object — is een eersteklas object dat kan worden doorgegeven, uitgebreid met extensiefuncties en interfaces kan implementeren.

Heeft companion object invloed op de prestaties?

Bij gebruik van const val voor primitieven en String — nul overhead, de waarde wordt in bytecode geïnlined. Voor methoden is er geen overhead als de methode niet inline is. In de meeste gevallen heeft companion object geen meetbare invloed op de prestaties. Gebruik @JvmStatic alleen voor de publieke API die vanuit Java wordt aangeroepen.

Samenvatting

  • companion object — Kotlin-mechanisme voor het declareren van statische leden van een klasse, ter vervanging van Java static
  • Eén companion object per klasse — groepeert alle statische elementen in één companion-object
  • Toegang via de klassenaam: ClassName.method() of ClassName.Companion.method()
  • @JvmStatic en @JvmField exporteren leden als echte statische methoden en velden voor Java
  • const val voor primitieven en String — lijnt de waarde tijdens compilatie in zonder overhead
  • Interfaces ondersteunen ook companion object voor constanten en fabrieksmethoden
  • Benoemde companion object verbetert de leesbaarheid van code en documenteert het doel van statische leden

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook