Ce face companion object
Kotlin nu are cuvântul static din Java. Membrii care țin de clasă în întregul ei (o constantă, o funcție de creare, un contor de obiecte create) se pun într-un companion object din interiorul clasei. Se folosesc cu numele clasei: Utilizator.MAX_LUNGIME, Utilizator.dinEmail("...").
Un companion este un obiect adevărat: poate avea un nume (companion object Fabrica; implicit se numește Companion), poate implementa interfețe și poate primi funcții de extensie (fun Utilizator.Companion.test()). Codul din companion vede membrii privați ai clasei, inclusiv un constructor private.
O clasă poate avea un singur companion object. Este creat o singură dată, la prima folosire a clasei.
Exemple
Exemplul 1: Funcție de creare și contor comun
Constructorul este privat, deci obiectele se creează doar prin nou, care numără câte au fost create.
class Bilet private constructor(val numar: Int, val spectacol: String) {
companion object {
private var vandute = 0
const val LOCURI = 3
fun nou(spectacol: String): Bilet? {
if (vandute == LOCURI) return null
vandute++
return Bilet(vandute, spectacol)
}
}
}
fun main() {
repeat(4) {
val b = Bilet.nou("Hamlet")
println(if (b == null) "Sală plină!" else "Bilet ${b.numar}/${Bilet.LOCURI} la ${b.spectacol}")
}
}
Rezultat
Bilet 1/3 la Hamlet
Bilet 2/3 la Hamlet
Bilet 3/3 la Hamlet
Sală plină!
Exemplul 2: Mai multe funcții de creare cu nume clare
În loc de mai mulți constructori, companion-ul oferă funcții cu nume care spun de unde vine valoarea.
class Temperatura private constructor(val celsius: Double) {
companion object {
fun dinCelsius(c: Double) = Temperatura(c)
fun dinFahrenheit(f: Double) = Temperatura((f - 32) * 5 / 9)
}
override fun toString() = "%.1f °C".format(celsius)
}
fun main() {
println(Temperatura.dinCelsius(21.5))
println(Temperatura.dinFahrenheit(98.6))
}
Rezultat
21.5 °C
37.0 °C
Exemplul 3: Companion cu nume care implementează o interfață
Fabrica implementează Parser, deci clasa Produs însăși poate fi dată unde se cere un Parser<Produs>.
interface Parser<T> { fun parseaza(text: String): T }
data class Produs(val nume: String, val pret: Int) {
companion object Fabrica : Parser<Produs> {
override fun parseaza(text: String): Produs {
val (nume, pret) = text.split(";")
return Produs(nume, pret.toInt())
}
}
}
fun <T> citesteToate(linii: List<String>, parser: Parser<T>) = linii.map { parser.parseaza(it) }
fun main() {
println(Produs.parseaza("Pâine;5"))
println(citesteToate(listOf("Lapte;8", "Ouă;12"), Produs))
println(Produs.Fabrica === Produs)
}
Rezultat
Produs(nume=Pâine, pret=5)
[Produs(nume=Lapte, pret=8), Produs(nume=Ouă, pret=12)]
true
Greșeli frecvente
- Căutarea lui
static: nu există în Kotlin. Foloseștecompanion objectsau funcții la nivelul de sus al fișierului. - Două blocuri
companion objectîn aceeași clasă: nu este permis. - Accesarea proprietăților unui obiect din companion: companion-ul nu are un
thisal obiectului (nu știe la care exemplar să se uite); primește obiectul ca parametru.
Comenzi înrudite
object: object declară o clasă cu un singur obiect (singleton) sau creează pe loc un obiect anonim care implementează o interfață.const val: const val declară o constantă cunoscută la compilare (număr, text, Boolean), înlocuită direct în cod.constructor și init: constructor declară un constructor secundar (sau unul primar cu modificatori); blocurile init rulează la crearea fiecărui obiect.class: class declară o clasă: un tip nou care grupează date (proprietăți) și comportament (metode).