companion object হল Kotlin ভাষার একটি মেকানিজম যা ক্লাসের স্ট্যাটিক সদস্য ঘোষণার জন্য Java-র static কীওয়ার্ড প্রতিস্থাপন করে। Kotlin-এ বিল্ট-ইন static নেই — এর পরিবর্তে, ক্লাসের ভিতরে companion মডিফায়ার সহ object ডিক্লেয়ারেশন ব্যবহার করা হয়। JetBrains, 2025 অনুসারে, companion object ক্লাসের নামের মাধ্যমে মেথড এবং প্রপার্টি কল করার অনুমতি দেয়, যা Java ইকোসিস্টেমে স্ট্যাটিক সদস্যদের সম্পূর্ণ সমতুল্য করে তোলে।
মূল পয়েন্ট
companion object হল Kotlin-এ object ডিক্লেয়ারেশন-এর একটি বিশেষ ধরন যা companion কীওয়ার্ড দিয়ে চিহ্নিত করা হয়। এটি এমন সদস্য ঘোষণা করার অনুমতি দেয় যা ক্লাসের ইনস্ট্যান্সের পরিবর্তে ক্লাসের অন্তর্গত — অর্থাৎ Java পরিভাষায় স্ট্যাটিক সদস্য। Java-এর বিপরীতে, যেখানে static পৃথক ফিল্ড এবং মেথডের জন্য একটি মডিফায়ার, Kotlin-এ স্ট্যাটিক সদস্যগুলি একটি single companion object-এর ভিতরে গ্রুপ করা হয়।
Kotlin-এ যেকোনো ক্লাসে ঠিক একটি companion object থাকতে পারে। এই অবজেক্টের সদস্যরা ইনস্ট্যান্স তৈরি না করেই ক্লাসের নামের মাধ্যমে অ্যাক্সেসযোগ্য: MyClass.method()। বাইটকোডের দৃষ্টিকোণ থেকে, companion object একটি পৃথক অভ্যন্তরীণ ক্লাসে কম্পাইল হয় এবং @JvmStatic অ্যানোটেশন ব্যবহার করলে এর মেথডগুলি বাইরের ক্লাসের স্ট্যাটিক মেথড হয়ে যায়।
Google I/O 2024 অনুসারে, Kotlin-এ লেখা আধুনিক Android অ্যাপ্লিকেশনে ফ্যাক্টরি মেথড, কনস্ট্যান্ট এবং ইউটিলিটি ফাংশনের জন্য companion object প্রধান প্যাটার্ন হয়ে উঠেছে। ডেভেলপাররা প্যাকেজ-লেভেল ফাংশন সহ ইউটিলিটি ক্লাসের পরিবর্তে এটি বেছে নেয় কারণ companion object মালিক ক্লাসের সাথে লজিক্যাল সংযোগ বজায় রাখে।
স্ট্যাটিক কনটেক্সট গ্রুপ করার জন্য companion object ব্যবহার করুন — কনস্ট্যান্ট, ফ্যাক্টরি, হেল্পার মেথড যা লজিক্যালি ক্লাসের অন্তর্গত কিন্তু ইনস্ট্যান্সের প্রয়োজন হয় না।
companion object-এর বেসিক সিনট্যাক্স সহজ: companion কীওয়ার্ডটি ক্লাসের ভিতরে object ডিক্লেয়ারেশনের আগে বসে। যদি কোনো নাম উল্লেখ না করা হয়, অবজেক্টটি Companion নাম পায়, যা স্পষ্টভাবে বা অপ্রত্যক্ষভাবে অ্যাক্সেস করা যেতে পারে।
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 via class name
val table = User.TABLE_NAME
val user = User.create("Alice")
উপরের উদাহরণে, TABLE_NAME এবং create() User.TABLE_NAME এবং User.create() এর মাধ্যমে অ্যাক্সেসযোগ্য। প্রিমিটিভ কনস্ট্যান্টের জন্য const মডিফায়ার লক্ষ্য করুন — এটি কম্পাইল-টাইম ভ্যালু ইনলাইনিং নিশ্চিত করে, যা প্রিমিটিভ এবং String-এর জন্য Java static final-এর মতো।
যদি companion object-এর কোনো নাম না থাকে, তবে এটি স্বয়ংক্রিয় নাম Companion: User.Companion.TABLE_NAME-এর মাধ্যমে অ্যাক্সেস করা যেতে পারে। বাস্তবে এটি খুব কমই প্রয়োজন, তবে Java কোড থেকে কল করার সময় বা রিফ্লেকশন ব্যবহার করার সময় উপকারী।
// Both calls are equivalent
User.create("Bob")
User.Companion.create("Bob")
// Getting reference to companion object
val companion: User.Companion = User
companion object-এর একটি নাম থাকতে পারে, যা কোড পঠনযোগ্যতা উন্নত করে এবং এটিকে অর্থপূর্ণ নামে অ্যাক্সেস করার অনুমতি দেয়। Factory হল ফ্যাক্টরি হিসেবে ব্যবহৃত companion object-এর জন্য সবচেয়ে সাধারণ নাম।
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 via Factory name
val response = HttpResponse.Factory.ok("data")
নামযুক্ত companion object স্ট্যাটিক সদস্যদের উদ্দেশ্য ডকুমেন্ট করতে সাহায্য করে। রিফ্যাক্টরিং-এ, নাম কোডকে স্ব-ডকুমেন্টিং করে তোলে — ডেভেলপার instantly দেখে যে Factory HttpResponse-এর ইনস্ট্যান্স তৈরি করে।
একটি ক্লাসে কেবল একটি companion object থাকতে পারে। এটি Java থেকে একটি মৌলিক পার্থক্য, যেখানে আপনি গ্রুপিং ছাড়াই যেকোনো সংখ্যক স্ট্যাটিক ফিল্ড এবং মেথড ঘোষণা করতে পারেন। যদি স্ট্যাটিক সদস্যদের একাধিক লজিক্যাল গ্রুপের প্রয়োজন হয়, companion ছাড়া নেস্টেড object ডিক্লেয়ারেশন ব্যবহার করুন।
অফিসিয়াল Kotlin ডকুমেন্টেশন (Kotlin Docs, 2025) অনুসারে, এক-companion-object সীমাবদ্ধতা ভাষা ডিজাইন দ্বারা অনুপ্রাণিত: স্ট্যাটিক সদস্যদের ক্লাসের সাথে দৃঢ়ভাবে সংযুক্ত থাকা উচিত এবং একটি companion object এই সংযোগের জন্য একটি স্পষ্ট সীমানা প্রদান করে। যদি খুব বেশি স্ট্যাটিক সদস্য থাকে, তবে এটি ক্লাস রিফ্যাক্টর করার সংকেত।
Kotlin-এ, ইন্টারফেসেও companion object থাকতে পারে। এটি সরাসরি ইন্টারফেসের ভিতরে স্ট্যাটিক মেথড এবং কনস্ট্যান্ট সংজ্ঞায়িত করার অনুমতি দেয়, যা Java-তে সম্ভব নয়। এই পদ্ধতি প্রায়শই ইন্টারফেসের সাথে সম্পর্কিত কনস্ট্যান্ট বা ফ্যাক্টরি মেথড ঘোষণার জন্য ব্যবহৃত হয়।
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)
}
}
এই উদাহরণে, BASE_URL, TIMEOUT_MS এবং create() ApiService ইন্টারফেসের অন্তর্গত, এর ইমপ্লিমেন্টেশন নয়। এটি সুবিধাজনক: সমস্ত কনস্ট্যান্ট এবং API সার্ভিস ইনস্ট্যান্স তৈরির ফ্যাক্টরি লজিক এক জায়গায় — ইন্টারফেসের ভিতরেই অবস্থিত।
ইন্টারফেস ইমপ্লিমেন্টেশনগুলি companion object-এর সদস্যদের ইনহেরিট করে না — এগুলি কেবল ইন্টারফেসের নাম: ApiService.BASE_URL-এর মাধ্যমে কল করা হয়।
Java কোড থেকে companion object মেথড কল করার সময়, ডিফল্টরূপে এগুলি বাইরের ক্লাসের স্ট্যাটিক মেথডের পরিবর্তে নেস্টেড Companion ক্লাসের মেথড হিসেবে অ্যাক্সেসযোগ্য। এগুলিকে Java-র জন্য বাস্তব স্ট্যাটিক মেথড এবং ফিল্ড হিসেবে এক্সপোর্ট করতে, মেথডের জন্য @JvmStatic এবং ফিল্ডের জন্য @JvmField অ্যানোটেশন ব্যবহার করুন।
| অ্যানোটেশন | প্রয়োগ | Java-তে ফলাফল |
|---|---|---|
| @JvmStatic | Companion object মেথড | স্ট্যাটিক মেথড: ClassName.method() |
| @JvmField | Companion object ফিল্ড | স্ট্যাটিক ফিল্ড: ClassName.field |
| const | প্রিমিটিভ এবং String | ইনলাইন কনস্ট্যান্ট: কম্পাইলার মান প্রতিস্থাপন করে |
| অ্যানোটেশন ছাড়া | ডিফল্টরূপে মেথড/ফিল্ড | 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"
}
}
// Called in Java as MathUtils.square(5), MathUtils.TAG
সমস্ত পাবলিক companion object মেথডের জন্য @JvmStatic ব্যবহার করার পরামর্শ দেওয়া হয় যা Java কোড থেকে অ্যাক্সেসযোগ্য হওয়া উচিত। const কেবল প্রিমিটিভ টাইপ এবং String-এ প্রয়োগ করা হয় — অন্যান্য টাইপের জন্য @JvmField ব্যবহার করুন।
বাস্তব প্রকল্পে, companion object বিভিন্ন মানক পরিস্থিতির জন্য ব্যবহৃত হয়। ফ্যাক্টরি মেথড সবচেয়ে সাধারণ প্যাটার্ন: বিভিন্ন সিগনেচার সহ একাধিক কনস্ট্রাক্টরের পরিবর্তে, 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>()
NetworkResult-এ companion object একটি ফ্যাক্টরি মেথড loading() প্রদান করে যা সঠিক generic টাইপ সহ একটি Loading ইনস্ট্যান্স তৈরি করে। এই মেথড ছাড়া, আপনাকে সরাসরি Loading()-এর মাধ্যমে ইনস্ট্যান্স তৈরি করতে হতো, যা অভ্যন্তরীণ ইমপ্লিমেন্টেশন উন্মুক্ত করে।
companion object প্রায়শই ক্লাস-নির্দিষ্ট কনস্ট্যান্ট সংরক্ষণের জন্য ব্যবহৃত হয়। const val দিয়ে ঘোষিত কনস্ট্যান্ট কম্পাইল টাইমে ইনলাইন হয়, যা রানটাইমে শূন্য ওভারহেড প্রদান করে।
class UserRepository {
companion object {
private const val TAG = "UserRepository"
private const val CACHE_SIZE = 100
private const val DEFAULT_PAGE_SIZE = 20
}
}
সচরাচর জিজ্ঞাসিত প্রশ্ন
সাধারণ object একটি পূর্ণাঙ্গ সিঙ্গলটন যা ক্লাস থেকে স্বাধীনভাবে বিদ্যমান। companion object হল ক্লাসের ভিতরে একটি object যার সদস্যরা বাইরের ক্লাসের নামের মাধ্যমে কল করা হয়। বাইটকোডে, companion object একটি স্ট্যাটিক নেস্টেড ক্লাসে পরিণত হয়, যখন সাধারণ object একটি স্বায়ত্তশাসিত সিঙ্গলটন ক্লাসে পরিণত হয়।
না, companion object সাবক্লাস দ্বারা ইনহেরিট হয় না। যদি ক্লাস B ক্লাস A-কে এক্সটেন্ড করে, তাহলে B.method() ক্লাস A-এর companion object থেকে মেথড কল করবে না — আপনাকে A.method()-এর মাধ্যমে কল করতে হবে। এটি Java-তে স্ট্যাটিক মেথডের আচরণের সাথে মেলে।
ডিফল্টরূপে — ClassName.Companion.method()-এর মাধ্যমে। এটিকে স্ট্যাটিক মেথড হিসেবে কল করতে, companion object মেথডে @JvmStatic যোগ করুন। ফিল্ডের জন্য, @JvmField ব্যবহার করুন বা প্রিমিটিভের জন্য const val দিয়ে ঘোষণা করুন।
Kotlin ডেভেলপাররা অবজেক্টের সাথে একীভূত কাজের জন্য static-এর পরিবর্তে companion object-কে অগ্রাধিকার দেওয়ার সিদ্ধান্ত নিয়েছে। Java-তে static OOP নীতি লঙ্ঘন করে কারণ স্ট্যাটিক মেথড কোনো ইনস্ট্যান্সের সাথে আবদ্ধ নয়। companion object একটি first-class অবজেক্ট যা পাস করা, এক্সটেনশন ফাংশন দিয়ে বাড়ানো এবং ইন্টারফেস ইমপ্লিমেন্ট করা যায়।
প্রিমিটিভ এবং String-এর জন্য const val ব্যবহার করলে — শূন্য ওভারহেড, মান বাইটকোডে ইনলাইন হয়। মেথডের জন্য, মেথড inline না হলে কোনো ওভারহেড নেই। বেশিরভাগ ক্ষেত্রে, companion object পারফরম্যান্সে কোনো পরিমাপযোগ্য প্রভাব তৈরি করে না। শুধুমাত্র Java থেকে কল করা পাবলিক API-র জন্য @JvmStatic ব্যবহার করুন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন