companion object — mecanismul limbajului Kotlin care înlocuiește cuvântul cheie static din Java pentru declararea membrilor statici ai clasei. În Kotlin nu există static încorporat — în schimb se folosește declarația object cu modificatorul companion în interiorul clasei. Conform JetBrains, 2025, companion object permite apelarea metodelor și proprietăților prin numele clasei, ceea ce le face echivalentul complet al membrilor statici în ecosistemul Java.
Principalele puncte
companion object — este o varietate specială de object declaration în limbajul Kotlin, marcată cu cuvântul cheie companion. Aceasta permite declararea membrilor care aparțin clasei, nu instanțelor sale — adică membri statici în terminologia Java. Spre deosebire de Java, unde static este un modificator pentru câmpuri și metode individuale, în Kotlin membrii statici sunt grupați într-un singur obiect companion.
Orice clasă în Kotlin poate conține exact un companion object. Membrii acestui obiect sunt accesibili prin numele clasei fără a crea o instanță: MyClass.method(). În același timp, din perspectiva bytecode-ului, companion object este compilat într-o clasă internă separată, iar metodele sale devin metode statice ale clasei exterioare atunci când se folosește adnotarea @JvmStatic.
Conform Google I/O 2024, companion object a devenit modelul principal pentru metode de fabrică, constante și funcții utilitare în aplicațiile Android moderne în Kotlin. Dezvoltatorii îl aleg în locul claselor utilitare cu funcții de pachet, deoarece companion object păstrează legătura logică cu clasa proprietară.
Folosiți companion object pentru gruparea contextului static — constante, fabrici, metode auxiliare care se referă logic la clasă, dar nu necesită o instanță.
Sintaxa de bază a companion object este simplă: cuvântul cheie companion se plasează înaintea declarației object în interiorul clasei. Dacă numele nu este specificat, obiectul primește numele Companion, la care se poate face referire explicit sau implicit.
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 }
}
// Acces prin numele clasei
val table = User.TABLE_NAME
val user = User.create("Alice")
În exemplul de mai sus TABLE_NAME și create() sunt accesibile prin User.TABLE_NAME și User.create(). Observați modificatorul const pentru constantele primitive — el garantează încorporarea valorii în faza de compilare, similar cu Java static final pentru primitive și String.
Dacă companion object nu are nume, se poate accesa prin numele automat Companion: User.Companion.TABLE_NAME. În practică, acest lucru este rar necesar, dar util la apelarea din cod Java sau la utilizarea reflexiei.
// Ambele apeluri sunt echivalente
User.create("Bob")
User.Companion.create("Bob")
// Obținerea referinței la companion object
val companion: User.Companion = User
companion object poate avea un nume, ceea ce îmbunătățește lizibilitatea codului și permite referirea la el printr-un nume clar. Factory — este cel mai comun nume pentru companion object utilizat ca fabrică.
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")
}
}
// Acces prin numele Factory
val response = HttpResponse.Factory.ok("data")
Companion object numit ajută la documentarea scopului membrilor statici. În refactorizare, numele face codul auto-documentat — dezvoltatorul vede imediat că Factory creează instanțe HttpResponse.
O clasă poate conține doar un companion object. Aceasta este o diferență fundamentală față de Java, unde se pot declara oricâte câmpuri și metode statice fără grupare. Dacă sunt necesare mai multe grupuri logice de membri statici, folosiți object declarations imbricate fără companion.
Conform documentației oficiale Kotlin (Kotlin Docs, 2025), limitarea la un companion object este motivată de designul limbajului: membrii statici trebuie să fie strâns legați de clasă, iar un singur obiect companion asigură o graniță clară a acestei legături. Dacă sunt prea mulți membri statici — acesta este un semnal pentru refactorizarea clasei.
În Kotlin, interfețele pot conține de asemenea companion object. Acest lucru permite definirea metodelor statice și constantelor direct în interiorul interfeței, ceea ce nu este posibil în Java. Această abordare este adesea folosită pentru declararea constantelor asociate interfeței sau a metodelor de fabrică.
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)
}
}
În acest exemplu, BASE_URL, TIMEOUT_MS și create() aparțin interfeței ApiService, nu implementărilor sale. Este convenabil: toate constantele și logica de fabrică pentru crearea instanței serviciului API se află într-un singur loc — în interiorul interfeței însăși.
Implementările interfeței nu moștenesc membrii companion object — aceștia se apelează doar prin numele interfeței: ApiService.BASE_URL.
La apelarea metodelor companion object din cod Java, acestea sunt disponibile implicit ca metode ale clasei imbricate Companion, nu ca metode statice ale clasei exterioare. Pentru a le exporta ca metode și câmpuri static reale pentru Java, folosiți adnotarea @JvmStatic pentru metode și @JvmField pentru câmpuri.
| Adnotare | Aplicare | Rezultat în Java |
|---|---|---|
| @JvmStatic | Metode companion object | Metodă statică: ClassName.method() |
| @JvmField | Câmpuri companion object | Câmp static: ClassName.field |
| const | Primitive și String | Constantă inline: compilatorul înlocuiește valoarea |
| fără adnotare | Metode/câmpuri implicite | 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"
}
}
// Apelat în Java ca MathUtils.square(5), MathUtils.TAG
Utilizarea @JvmStatic este recomandată pentru toate metodele publice ale companion object care trebuie să fie accesibile din cod Java. const se aplică doar tipurilor primitive și String — pentru celelalte tipuri folosiți @JvmField.
În proiecte reale, companion object este utilizat pentru câteva scenarii standard. Metodele de fabrică — cel mai comun model: în locul mai multor constructori cu semnături diferite, se folosesc metode de fabrică denumite în 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 din NetworkResult oferă metoda de fabrică loading() care creează o instanță Loading cu tipul generic corect. Fără această metodă, ar trebui să creați instanța direct prin Loading(), ceea ce dezvăluie implementarea internă.
Adesea companion object este folosit pentru stocarea constantelor specifice clasei. Constantele declarate cu const val sunt încorporate în faza de compilare, oferind un overhead zero în runtime.
class UserRepository {
companion object {
private const val TAG = "UserRepository"
private const val CACHE_SIZE = 100
private const val DEFAULT_PAGE_SIZE = 20
}
}
Întrebări frecvente
ordinary object — este un singleton complet, care există independent de clasă. companion object — este un object în interiorul clasei, ai cărui membri sunt apelați prin numele clasei exterioare. În bytecode, companion object devine o clasă imbricată statică, iar object obișnuit devine o clasă singleton autonomă.
Nu, companion object nu este moștenit de subclase. Dacă clasa B moștenește clasa A, B.method() nu va apela metoda din companion object al clasei A — trebuie să accesați prin A.method(). Aceasta corespunde comportamentului metodelor statice în Java.
Implicit — prin ClassName.Companion.method(). Pentru a apela ca metodă statică, adăugați @JvmStatic la metoda companion object. Pentru câmpuri folosiți @JvmField sau declarați-le cu const val pentru primitive.
Dezvoltatorii Kotlin au decis să renunțe la static în favoarea companion object pentru o lucrare uniformă cu obiectele. static în Java încalcă principiile OOP, deoarece metodele statice nu sunt legate de o instanță. companion object — este un obiect de primă clasă care poate fi transmis, extins cu funcții de extensie și poate implementa interfețe.
La utilizarea const val pentru primitive și String — overhead zero, valoarea este încorporată în bytecode. Pentru metode nu există overhead dacă metoda nu este inline. În majoritatea cazurilor, companion object nu are un impact măsurabil asupra performanței. Folosiți @JvmStatic doar pentru API-ul public apelat din Java.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și