companion object — mekanismo ng wikang Kotlin na pumapalit sa keyword na static mula sa Java para sa pagdedeklara ng mga static na miyembro ng klase. Sa Kotlin walang built-in na static — sa halip ay ginagamit ang deklarasyon ng object na may modifier na companion sa loob ng klase. Ayon sa JetBrains, 2025, pinapayagan ng companion object ang pagtawag ng mga metodo at property sa pamamagitan ng pangalan ng klase, na ginagawa silang kumpletong katumbas ng mga static na miyembro sa Java ecosystem.
Mga Pangunahing Punto
companion object — ay isang espesyal na uri ng object declaration sa wikang Kotlin na minamarkahan ng keyword na companion. Pinapayagan nito ang pagdedeklara ng mga miyembro na pag-aari ng klase, hindi ng mga instance nito — iyon ay mga static na miyembro sa terminolohiya ng Java. Hindi tulad ng Java kung saan ang static ay isang modifier para sa mga indibidwal na field at metodo, sa Kotlin ang mga static na miyembro ay pinagsama-sama sa loob ng isang object na kasama.
Anumang klase sa Kotlin ay maaaring maglaman ng eksaktong isang companion object. Ang mga miyembro ng object na ito ay maa-access sa pamamagitan ng pangalan ng klase nang hindi gumagawa ng instance: MyClass.method(). Samantala mula sa pananaw ng bytecode, ang companion object ay na-compile sa isang hiwalay na panloob na klase, at ang mga metodo nito ay nagiging static na metodo ng panlabas na klase kapag ginagamit ang anotasyong @JvmStatic.
Ayon sa Google I/O 2024, ang companion object ay naging pangunahing pattern para sa mga factory method, constant, at utility function sa modernong Android application sa Kotlin. Pinipili ito ng mga developer kaysa sa mga utility class na may package function, dahil pinapanatili ng companion object ang lohikal na koneksyon sa klase na may-ari.
Gamitin ang companion object para sa pagpapangkat ng static na konteksto — mga constant, factory, helper method na lohikal na nauugnay sa klase ngunit hindi nangangailangan ng instance.
Ang pangunahing syntax ng companion object ay simple: ang keyword na companion ay inilalagay bago ang deklarasyon ng object sa loob ng klase. Kung hindi tinukoy ang pangalan, ang object ay makakakuha ng pangalang Companion, na maaaring ma-access nang tahasan o hindi tahasan.
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 }
}
// Access sa pamamagitan ng pangalan ng klase
val table = User.TABLE_NAME
val user = User.create("Alice")
Sa halimbawa sa itaas ang TABLE_NAME at create() ay maa-access sa pamamagitan ng User.TABLE_NAME at User.create(). Pansinin ang modifier na const para sa mga primitive na constant — ginagarantiyahan nito ang pag-embed ng halaga sa yugto ng compilation, katulad ng Java static final para sa primitives at String.
Kung ang companion object ay walang pangalan, maaari itong ma-access sa pamamagitan ng awtomatikong pangalan na Companion: User.Companion.TABLE_NAME. Sa praktika ito ay bihirang kailanganin, ngunit kapaki-pakinabang sa pagtawag mula sa Java code o kapag gumagamit ng reflection.
// Parehong tawag ay katumbas
User.create("Bob")
User.Companion.create("Bob")
// Pagkuha ng reference sa companion object
val companion: User.Companion = User
Ang companion object ay maaaring magkaroon ng pangalan, na nagpapabuti sa pagiging nababasa ng code at nagbibigay-daan sa pag-access nito sa pamamagitan ng isang nauunawaang pangalan. Factory — ang pinakakaraniwang pangalan para sa companion object na ginagamit bilang pabrika.
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")
}
}
// Access sa pamamagitan ng pangalan ng Factory
val response = HttpResponse.Factory.ok("data")
Ang pinangalanang companion object ay tumutulong sa pagdokumento ng layunin ng mga static na miyembro. Sa refactoring, ang pangalan ay ginagawang self-documenting ang code — nakikita agad ng developer na ang Factory ay lumilikha ng mga instance ng HttpResponse.
Ang isang klase ay maaari lamang maglaman ng isang companion object. Ito ay isang pangunahing pagkakaiba mula sa Java, kung saan maraming static na field at metodo ay maaaring ideklara nang walang pagpapangkat. Kung kinakailangan ang maraming lohikal na grupo ng mga static na miyembro, gumamit ng mga nested object declarations na walang companion.
Ayon sa opisyal na dokumentasyon ng Kotlin (Kotlin Docs, 2025), ang limitasyon sa isang companion object ay naudyok ng disenyo ng wika: ang mga static na miyembro ay dapat na malapit na nauugnay sa klase, at isang object na kasama ay nagbibigay ng malinaw na hangganan ng ugnayang ito. Kung masyadong maraming static na miyembro — ito ay senyales para sa refactoring ng klase.
Sa Kotlin, ang mga interface ay maaari ring maglaman ng companion object. Ito ay nagpapahintulot sa pagtukoy ng mga static na metodo at constant nang direkta sa loob ng interface, na hindi posible sa Java. Ang diskarteng ito ay kadalasang ginagamit para sa pagdedeklara ng mga constant na nauugnay sa interface o mga factory method.
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)
}
}
Sa halimbawang ito ang BASE_URL, TIMEOUT_MS at create() ay pag-aari ng interface na ApiService, hindi ng mga implementasyon nito. Ito ay maginhawa: lahat ng constant at factory logic para sa paglikha ng instance ng API service ay nasa isang lugar — sa loob ng interface mismo.
Ang mga implementasyon ng interface ay hindi nagmamana ng mga miyembro ng companion object — sila ay tinatawag lamang sa pamamagitan ng pangalan ng interface: ApiService.BASE_URL.
Sa pagtawag ng mga metodo ng companion object mula sa Java code, ang mga ito ay default na available bilang mga metodo ng nested class na Companion, hindi bilang mga static na metodo ng panlabas na klase. Upang i-export ang mga ito bilang tunay na static metodo at field para sa Java, gamitin ang anotasyong @JvmStatic para sa mga metodo at @JvmField para sa mga field.
| Anotasyon | Aplikasyon | Resulta sa Java |
|---|---|---|
| @JvmStatic | Mga metodo ng companion object | Static metodo: ClassName.method() |
| @JvmField | Mga field ng companion object | Static field: ClassName.field |
| const | Mga primitive at String | Inline constant: compiler ang nagpapalit ng halaga |
| walang anotasyon | Default na metodo/field | 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"
}
}
// Tinatawag sa Java bilang MathUtils.square(5), MathUtils.TAG
Ang paggamit ng @JvmStatic ay inirerekomenda para sa lahat ng pampublikong metodo ng companion object na dapat ma-access mula sa Java code. Ang const ay inilalapat lamang sa mga primitive na uri at String — para sa iba pang uri gamitin ang @JvmField.
Sa tunay na mga proyekto, ang companion object ay ginagamit para sa ilang karaniwang sitwasyon. Mga factory method — ang pinakakaraniwang pattern: sa halip na maraming constructor na may iba't ibang lagda, ginagamit ang mga pinangalanang factory method sa 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>()
Ang companion object sa NetworkResult ay nagbibigay ng factory method na loading() na lumilikha ng instance ng Loading na may tamang generic na uri. Kung wala ang metodong ito, kailangan mong gumawa ng instance nang direkta sa pamamagitan ng Loading(), na naglalantad ng panloob na implementasyon.
Madalas ginagamit ang companion object para sa pag-iimbak ng mga constant na tiyak sa klase. Ang mga constant na idineklara na may const val ay na-embed sa yugto ng compilation, na nagbibigay ng zero overhead sa runtime.
class UserRepository {
companion object {
private const val TAG = "UserRepository"
private const val CACHE_SIZE = 100
private const val DEFAULT_PAGE_SIZE = 20
}
}
Mga Madalas Itanong
Ang ordinaryong object — ay isang ganap na singleton na umiiral nang independiyente sa klase. companion object — ay isang object sa loob ng klase na ang mga miyembro ay tinatawag sa pamamagitan ng pangalan ng panlabas na klase. Sa bytecode, ang companion object ay nagiging isang static na nested class, at ang ordinaryong object ay nagiging isang autonomong singleton class.
Hindi, ang companion object ay hindi minamana ng mga subclass. Kung ang klase B ay nagmamana ng klase A, ang B.method() ay hindi tatawag ng metodo mula sa companion object ng klase A — kailangan i-access sa pamamagitan ng A.method(). Ito ay tumutugma sa pag-uugali ng mga static na metodo sa Java.
Default — sa pamamagitan ng ClassName.Companion.method(). Upang tumawag bilang static na metodo, magdagdag ng @JvmStatic sa metodo ng companion object. Para sa mga field gamitin ang @JvmField o ideklara ang mga ito na may const val para sa mga primitive.
Nagpasya ang mga developer ng Kotlin na iwanan ang static pabor sa companion object para sa pare-parehong pagtatrabaho sa mga object. Ang static sa Java ay lumalabag sa mga prinsipyo ng OOP dahil ang mga static na metodo ay hindi nakatali sa isang instance. Ang companion object — ay isang first-class na object na maaaring ipasa, palawakin gamit ang extension functions, at magpatupad ng mga interface.
Sa paggamit ng const val para sa mga primitive at String — zero overhead, ang halaga ay na-embed sa bytecode. Para sa mga metodo walang overhead kung ang metodo ay hindi inline. Sa karamihan ng mga kaso, ang companion object ay walang nasusukat na epekto sa pagganap. Gamitin ang @JvmStatic lamang para sa pampublikong API na tinatawag mula sa Java.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din