Het declareren van constanten en het gebruik van companion objects zijn belangrijke concepten in Kotlin, die de vertrouwde static-leden uit Java vervangen en de daarvoor geldende moeilijkheden bij het oversteken van de OOP- en functionele programmeerparadigma's aanpakken.
Achtergrond: In Java worden constanten meestal gedefinieerd met static final velden, en statische methoden worden gebruikt voor hulpfuncties of fabrieksfuncties. In Kotlin zijn object en companion object geïntroduceerd in plaats van static, en voor compile-time constanten is het trefwoord const ontwikkeld.
Probleem: Waarden moeten worden gedeclareerd die niet afhankelijk zijn van een klasse-instantie, en ook fabrieksmethoden en statische toestanden moeten worden georganiseerd zonder de integriteit van OOP te schaden.
Oplossing: Companion objects worden gedeclareerd binnen een klasse en stellen je in staat om leden te plaatsen die gemeenschappelijk zijn voor alle instanties:
Voorbeeld code:
class MyClass { companion object { const val DEFAULT_LIMIT = 10 fun create(): MyClass = MyClass() } } val limit = MyClass.DEFAULT_LIMIT val instance = MyClass.create()
Belangrijke kenmerken:
Kan een companion object meerdere instanties in een klasse hebben?
Nee, er kan maar één companion object per klasse zijn. Pogingen om een tweede te declareren leiden tot een compileerfout. Maar binnen het companion object zijn er geen beperkingen aan het aantal methoden/eigenschappen.
Kun je lateinit variabelen initialiseren binnen een companion object?
Nee, omdat eigenschappen met const of variabelen binnen een companion object direct moeten worden geïnitialiseerd of moeten zijn val/var met expliciete initialisatie. lateinit is niet toegestaan voor eigenschappen binnen een companion object.
Kan een companion object een eigen naam hebben en wanneer is dit vereist?
Ja, de naam van de companion object wordt expliciet toegewezen als je er bij naam naar wilt verwijzen of bijvoorbeeld interfaces wilt implementeren. In andere gevallen is het optioneel. Voorbeeld:
class Foo { companion object Factory { fun create(): Foo = Foo() } } val instance = Foo.Factory.create()
Alle hulpfuncties en globale variabelen van het programma worden in één companion object geplaatst, en var wordt in plaats van val/const gebruikt:
Voordelen:
Nadelen:
Er worden alleen compile-time constanten (const val) en pure functions binnen het companion object gebruikt, alles dat veranderbaar is, is of gelokaliseerd of doorgegeven via DI:
Voordelen:
Nadelen: