Companion object στην Kotlin: τι είναι, σύνταξη και εφαρμογή

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-06-21 Χρόνος ανάγνωσης: 9 λεπ

companion object — ο μηχανισμός της γλώσσας Kotlin που αντικαθιστά τη λέξη-κλειδί static από τη Java για τη δήλωση στατικών μελών μιας κλάσης. Στην Kotlin δεν υπάρχει ενσωματωμένο static — αντίθετα χρησιμοποιείται δήλωση object με τον τροποποιητή companion μέσα στην κλάση. Σύμφωνα με το JetBrains, 2025, το companion object επιτρέπει την κλήση μεθόδων και ιδιοτήτων μέσω του ονόματος της κλάσης, καθιστώντας τα πλήρες αντίστοιχο των στατικών μελών στο οικοσύστημα Java.

Κύρια σημεία

  • companion object — δήλωση object μέσα στην κλάση με τη λέξη-κλειδί companion, αντικαθιστώντας το Java static
  • Στατικά μέλη είναι προσβάσιμα μέσω του ονόματος της κλάσης χωρίς δημιουργία στιγμιοτύπου: ClassName.method()
  • Ονομασμένο companion object επιτρέπει την ονομασία του αντικειμένου για πιο ευανάγνωστο κώδικα
  • Διεπαφές στην Kotlin μπορούν επίσης να περιέχουν companion object με υλοποίηση μεθόδων
  • @JvmStatic — σχολιασμός για εξαγωγή μεθόδων companion object ως πραγματικών static-μεθόδων σε Java

Τι είναι το companion object στην Kotlin;

companion object — είναι μια ειδική ποικιλία object declaration στη γλώσσα Kotlin, που σημειώνεται με τη λέξη-κλειδί companion. Επιτρέπει τη δήλωση μελών που ανήκουν στην κλάση, όχι στα στιγμιότυπά της — δηλαδή στατικά μέλη στην ορολογία Java. Σε αντίθεση με τη Java, όπου το static είναι τροποποιητής για μεμονωμένα πεδία και μεθόδους, στην Kotlin τα στατικά μέλη ομαδοποιούνται μέσα σε ένα αντικείμενο-σύντροφο.

Οποιαδήποτε κλάση στην Kotlin μπορεί να περιέχει ακριβώς ένα companion object. Τα μέλη αυτού του αντικειμένου είναι προσβάσιμα μέσω του ονόματος της κλάσης χωρίς δημιουργία στιγμιοτύπου: MyClass.method(). Ταυτόχρονα από άποψη bytecode, το companion object μεταγλωττίζεται σε ξεχωριστή εσωτερική κλάση και οι μέθοδοί του γίνονται στατικές μέθοδοι της εξωτερικής κλάσης όταν χρησιμοποιείται ο σχολιασμός @JvmStatic.

Σύμφωνα με το Google I/O 2024, το companion object έχει γίνει το κύριο πρότυπο για μεθόδους εργοστασίου, σταθερές και βοηθητικές συναρτήσεις σε σύγχρονες εφαρμογές Android σε Kotlin. Οι προγραμματιστές το επιλέγουν αντί για βοηθητικές κλάσεις με συναρτήσεις πακέτου, επειδή το companion object διατηρεί τη λογική σύνδεση με την κλάση-ιδιοκτήτη.

Χρησιμοποιήστε companion object για ομαδοποίηση στατικού περιβάλλοντος — σταθερές, εργοστάσια, βοηθητικές μεθόδους που λογικά ανήκουν στην κλάση αλλά δεν απαιτούν στιγμιότυπο.

Σύνταξη companion object: δήλωση και πρόσβαση

Η βασική σύνταξη του companion object είναι απλή: η λέξη-κλειδί companion τοποθετείται μπροστά από τη δήλωση object μέσα στην κλάση. Αν δεν δοθεί όνομα, το αντικείμενο λαμβάνει το όνομα Companion, στο οποίο μπορεί κανείς να αναφερθεί ρητά ή σιωπηρά.

kotlin
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 }
}

// Πρόσβαση μέσω ονόματος κλάσης
val table = User.TABLE_NAME
val user = User.create("Alice")

Στο παραπάνω παράδειγμα τα TABLE_NAME και create() είναι προσβάσιμα μέσω User.TABLE_NAME και User.create(). Παρατηρήστε τον τροποποιητή const για σταθερές πρωτόγονων τύπων — εγγυάται την ενσωμάτωση της τιμής κατά τη μεταγλώττιση, ανάλογα με το Java static final για primitive και String.

Σιωπηρή και ρητή πρόσβαση μέσω Companion

Αν το companion object δεν έχει όνομα, μπορεί κανείς να έχει πρόσβαση μέσω του αυτόματου ονόματος Companion: User.Companion.TABLE_NAME. Στην πράξη αυτό σπάνια χρειάζεται, αλλά είναι χρήσιμο κατά την κλήση από κώδικα Java ή κατά τη χρήση ανάκλασης.

kotlin
// Και οι δύο κλήσεις είναι ισοδύναμες
User.create("Bob")
User.Companion.create("Bob")

// Λήψη αναφοράς σε companion object
val companion: User.Companion = User

Ονομασμένο companion object και χαρακτηριστικά

Το companion object μπορεί να έχει όνομα, βελτιώνοντας την αναγνωσιμότητα του κώδικα και επιτρέποντας την πρόσβαση με ένα κατανοητό όνομα. Factory — το πιο κοινό όνομα για companion object που χρησιμοποιείται ως εργοστάσιο.

kotlin
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")
    }
}

// Πρόσβαση μέσω ονόματος Factory
val response = HttpResponse.Factory.ok("data")

Το ονομασμένο companion object βοηθά στην τεκμηρίωση του σκοπού των στατικών μελών. Στην αναδόμηση, το όνομα καθιστά τον κώδικα αυτο-τεκμηριωμένο — ο προγραμματιστής βλέπει αμέσως ότι το Factory δημιουργεί στιγμιότυπα HttpResponse.

Περιορισμός: ακριβώς ένα companion object ανά κλάση

Μια κλάση μπορεί να περιέχει μόνο ένα companion object. Αυτή είναι μια θεμελιώδης διαφορά από τη Java, όπου μπορούν να δηλωθούν οποιαδήποτε στατικά πεδία και μέθοδοι χωρίς ομαδοποίηση. Αν απαιτούνται πολλές λογικές ομάδες στατικών μελών, χρησιμοποιήστε ένθετες δηλώσεις object χωρίς companion.

Σύμφωνα με την επίσημη τεκμηρίωση της Kotlin (Kotlin Docs, 2025), ο περιορισμός σε ένα companion object δικαιολογείται από τον σχεδιασμό της γλώσσας: τα στατικά μέλη πρέπει να συνδέονται στενά με την κλάση και ένα αντικείμενο-σύντροφος παρέχει ένα σαφές όριο αυτής της σύνδεσης. Αν υπάρχουν πάρα πολλά στατικά μέλη — αυτό είναι σήμα για αναδόμηση της κλάσης.

Companion object σε διεπαφές

Στην Kotlin, οι διεπαφές μπορούν επίσης να περιέχουν companion object. Αυτό επιτρέπει τον ορισμό στατικών μεθόδων και σταθερών απευθείας μέσα στη διεπαφή, κάτι που δεν είναι δυνατό στη Java. Αυτή η προσέγγιση χρησιμοποιείται συχνά για τη δήλωση σταθερών που σχετίζονται με τη διεπαφή ή μεθόδων εργοστασίου.

kotlin
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.

@JvmStatic και @JvmField: συμβατότητα με Java

Κατά την κλήση μεθόδων companion object από κώδικα Java, είναι προεπιλεγμένα διαθέσιμες ως μέθοδοι της ένθετης κλάσης Companion, όχι ως στατικές μέθοδοι της εξωτερικής κλάσης. Για να τις εξαγάγετε ως πραγματικές static μεθόδους και πεδία για Java, χρησιμοποιήστε τον σχολιασμό @JvmStatic για μεθόδους και @JvmField για πεδία.

ΣχολιασμόςΕφαρμογήΑποτέλεσμα σε Java
@JvmStaticΜέθοδοι companion objectΣτατική μέθοδος: ClassName.method()
@JvmFieldΠεδία companion objectΣτατικό πεδίο: ClassName.field
constPrimitive και StringInline σταθερά: μεταγλωττιστής υποκαθιστά την τιμή
χωρίς σχολιασμόΠροεπιλεγμένες μέθοδοι/πεδίαCompanion.method() / Companion.field
kotlin
class MathUtils {
    companion object {
        const val PI = 3.14159

        @JvmStatic
        fun square(x: Int): Int = x * x

        @JvmField
        val TAG: String = "MathUtils"
    }
}

// Καλείται σε Java ως MathUtils.square(5), MathUtils.TAG

Η χρήση @JvmStatic συνιστάται για όλες τις δημόσιες μεθόδους companion object που πρέπει να είναι προσβάσιμες από κώδικα Java. Το const εφαρμόζεται μόνο σε primitive τύπους και String — για άλλους τύπους χρησιμοποιήστε @JvmField.

Πρακτικά παραδείγματα χρήσης companion object

Σε πραγματικά έργα, το companion object χρησιμοποιείται για αρκετά τυπικά σενάρια. Μέθοδοι εργοστασίου — το πιο κοινό πρότυπο: αντί για πολλούς κατασκευαστές με διαφορετικές υπογραφές, χρησιμοποιούνται ονομασμένες μέθοδοι εργοστασίου στο companion object.

kotlin
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 στο NetworkResult παρέχει τη μέθοδο εργοστασίου loading() που δημιουργεί ένα στιγμιότυπο Loading με τον σωστό generic τύπο. Χωρίς αυτή τη μέθοδο, θα έπρεπε να δημιουργήσετε στιγμιότυπο απευθείας μέσω Loading(), που αποκαλύπτει την εσωτερική υλοποίηση.

Σταθερές και ετικέτες για καταγραφή

Συχνά το companion object χρησιμοποιείται για αποθήκευση σταθερών ειδικών για την κλάση. Οι σταθερές που δηλώνονται με const val ενσωματώνονται κατά τη μεταγλώττιση, παρέχοντας μηδενική επιβάρυνση κατά τον χρόνο εκτέλεσης.

kotlin
class UserRepository {
    companion object {
        private const val TAG = "UserRepository"
        private const val CACHE_SIZE = 100
        private const val DEFAULT_PAGE_SIZE = 20
    }
}

Συχνές Ερωτήσεις

Τι διαφορά έχει το companion object από το συνηθισμένο object στην Kotlin;

Το ordinary object — είναι ένα πλήρες singleton που υπάρχει ανεξάρτητα από την κλάση. companion object — είναι ένα object μέσα στην κλάση του οποίου τα μέλη καλούνται μέσω του ονόματος της εξωτερικής κλάσης. Στο bytecode, το companion object γίνεται στατική ένθετη κλάση, ενώ το συνηθισμένο object γίνεται αυτόνομη singleton κλάση.

Μπορεί να κληρονομηθεί το companion object;

Όχι, το companion object δεν κληρονομείται από υποκλάσεις. Αν η κλάση B κληρονομεί την κλάση A, η B.method() δεν θα καλέσει μέθοδο από το companion object της κλάσης A — πρέπει να γίνει πρόσβαση μέσω A.method(). Αυτό αντιστοιχεί στη συμπεριφορά των στατικών μεθόδων στη Java.

Πώς καλώ companion object από κώδικα Java;

Προεπιλεγμένα — μέσω ClassName.Companion.method(). Για να καλέσετε ως στατική μέθοδο, προσθέστε @JvmStatic στη μέθοδο companion object. Για πεδία χρησιμοποιήστε @JvmField ή δηλώστε τα με const val για primitive.

Γιατί η Kotlin δεν έχει λέξη-κλειδί static;

Οι προγραμματιστές της Kotlin αποφάσισαν να εγκαταλείψουν το static υπέρ του companion object για ομοιόμορφη εργασία με αντικείμενα. Το static στη Java παραβιάζει τις αρχές OOP, επειδή οι στατικές μέθοδοι δεν συνδέονται με ένα στιγμιότυπο. Το companion object — είναι αντικείμενο πρώτης τάξης που μπορεί να μεταβιβαστεί, να επεκταθεί με συναρτήσεις επέκτασης και να υλοποιήσει διεπαφές.

Επηρεάζει το companion object την απόδοση;

Κατά τη χρήση const val για primitive και String — μηδενική επιβάρυνση, η τιμή ενσωματώνεται στο bytecode. Για μεθόδους δεν υπάρχει επιβάρυνση αν η μέθοδος δεν είναι inline. Στις περισσότερες περιπτώσεις, το companion object δεν έχει μετρήσιμη επίδραση στην απόδοση. Χρησιμοποιήστε @JvmStatic μόνο για δημόσιο API που καλείται από Java.

Σύνοψη

  • companion object — μηχανισμός Kotlin για δήλωση στατικών μελών κλάσης, αντικαθιστώντας το Java static
  • Ένα companion object ανά κλάση — ομαδοποιεί όλα τα στατικά στοιχεία σε ένα αντικείμενο-σύντροφο
  • Πρόσβαση μέσω ονόματος κλάσης: ClassName.method() ή ClassName.Companion.method()
  • @JvmStatic και @JvmField εξάγουν μέλη ως πραγματικές στατικές μεθόδους και πεδία για Java
  • const val για primitive και String — ενσωματώνει την τιμή κατά τη μεταγλώττιση χωρίς επιβάρυνση
  • Διεπαφές υποστηρίζουν επίσης companion object για σταθερές και μεθόδους εργοστασίου
  • Ονομασμένο companion object βελτιώνει την αναγνωσιμότητα και αυτο-τεκμηριώνει τον σκοπό των στατικών μελών

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης