companion object ist ein Mechanismus der Sprache Kotlin, der das Java-Schlüsselwort static für die Deklaration statischer Klassenmember ersetzt. Kotlin hat kein eingebautes static — stattdessen wird eine object-Deklaration mit dem Modifikator companion innerhalb einer Klasse verwendet. Laut JetBrains, 2025 erlaubt companion object, Methoden und Eigenschaften über den Klassennamen aufzurufen, was sie zum vollwertigen Äquivalent statischer Member im Java-Ökosystem macht.
Wichtige Punkte
companion object ist eine besondere Art der object-Deklaration in Kotlin, die mit dem Schlüsselwort companion markiert wird. Sie erlaubt es, Member zu deklarieren, die zur Klasse und nicht zu ihren Instanzen gehören — also statische Member im Java-Sinne. Anders als in Java, wo static ein Modifikator für einzelne Felder und Methoden ist, werden in Kotlin statische Member innerhalb eines einzelnen Begleitobjekts gruppiert.
Jede Klasse in Kotlin kann genau ein companion object enthalten. Die Member dieses Objekts sind über den Klassennamen ohne Erstellung einer Instanz zugänglich: MyClass.method(). In Bytecode-Hinsicht wird ein companion object in eine separate innere Klasse kompiliert, und seine Methoden werden bei Verwendung der @JvmStatic-Annotation zu statischen Methoden der äußeren Klasse.
Laut Google I/O 2024 ist companion object zum Hauptmuster für Factory-Methoden, Konstanten und Hilfsfunktionen in modernen Android-Anwendungen in Kotlin geworden. Entwickler wählen es statt Utility-Klassen mit Paketlevel-Funktionen, da companion object eine logische Verbindung zur besitzenden Klasse beibehält.
Verwenden Sie companion object zum Gruppieren von statischem Kontext — Konstanten, Factorys, Hilfsmethoden, die logisch zur Klasse gehören, aber keine Instanz benötigen.
Die grundlegende Syntax von companion object ist einfach: Das Schlüsselwort companion wird vor die object-Deklaration innerhalb der Klasse gesetzt. Wenn kein Name angegeben wird, erhält das Objekt den Namen Companion, auf den explizit oder implizit zugegriffen werden kann.
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")
Im obigen Beispiel sind TABLE_NAME und create() über User.TABLE_NAME und User.create() zugänglich. Beachten Sie den const-Modifikator für primitive Konstanten — er garantiert die Inline-Setzung des Werts zur Kompilierzeit, ähnlich wie Java static final für primitive Typen und String.
Wenn ein companion object keinen Namen hat, kann über den automatischen Namen Companion: User.Companion.TABLE_NAME darauf zugegriffen werden. In der Praxis wird dies selten benötigt, ist aber beim Aufruf aus Java-Code oder bei Verwendung von Reflexion nützlich.
// Both calls are equivalent
User.create("Bob")
User.Companion.create("Bob")
// Getting reference to companion object
val companion: User.Companion = User
Ein companion object kann einen Namen haben, was die Lesbarkeit des Codes verbessert und den Zugriff über einen aussagekräftigen Namen erlaubt. Factory ist der häufigste Name für ein als Factory verwendetes 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")
Ein benannter companion object hilft, den Zweck statischer Member zu dokumentieren. Bei der Refaktorierung macht der Name den Code selbstdokumentierend — der Entwickler sieht sofort, dass Factory Instanzen von HttpResponse erstellt.
Eine Klasse kann nur ein companion object enthalten. Dies ist ein grundlegender Unterschied zu Java, wo Sie beliebig viele statische Felder und Methoden ohne Gruppierung deklarieren können. Wenn mehrere logische Gruppen statischer Member benötigt werden, verwenden Sie verschachtelte object-Deklarationen ohne companion.
Laut der offiziellen Kotlin-Dokumentation (Kotlin Docs, 2025) ist die Beschränkung auf ein companion object durch das Sprachdesign motiviert: Statische Member sollten eng mit der Klasse gekoppelt sein, und ein Begleitobjekt bietet eine klare Grenze für diese Verbindung. Wenn es zu viele statische Member gibt, ist dies ein Signal zur Refaktorierung der Klasse.
In Kotlin können auch Schnittstellen ein companion object enthalten. Dies erlaubt es, statische Methoden und Konstanten direkt innerhalb einer Schnittstelle zu definieren, was in Java nicht möglich ist. Dieser Ansatz wird häufig zur Deklaration von Konstanten, die mit der Schnittstelle verbunden sind, oder von Factory-Methoden verwendet.
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)
}
}
In diesem Beispiel gehören BASE_URL, TIMEOUT_MS und create() zur ApiService-Schnittstelle, nicht zu ihren Implementierungen. Dies ist praktisch: Alle Konstanten und die Factory-Logik zum Erstellen einer API-Dienstinstanz befinden sich an einem Ort — innerhalb der Schnittstelle selbst.
Implementierungen der Schnittstelle erben die Member des companion object nicht — sie werden nur über den Schnittstellennamen aufgerufen: ApiService.BASE_URL.
Beim Aufruf von companion object-Methoden aus Java-Code sind sie standardmäßig als Methoden der verschachtelten Companion-Klasse zugänglich, nicht als statische Methoden der äußeren Klasse. Um sie als echte statische Methoden und Felder für Java zu exportieren, verwenden Sie die @JvmStatic-Annotation für Methoden und @JvmField für Felder.
| Annotation | Anwendung | Ergebnis in Java |
|---|---|---|
| @JvmStatic | Companion object-Methoden | Statische Methode: ClassName.method() |
| @JvmField | Companion object-Felder | Statisches Feld: ClassName.field |
| const | Primitive Typen und String | Inline-Konstante: Compiler ersetzt den Wert |
| ohne Annotation | Methoden/Felder standardmäßig | 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
Die Verwendung von @JvmStatic wird für alle öffentlichen companion object-Methoden empfohlen, die aus Java-Code zugänglich sein sollen. const wird nur auf primitive Typen und String angewendet — für andere Typen verwenden Sie @JvmField.
In realen Projekten wird companion object für mehrere Standardszenarien verwendet. Factory-Methoden sind das häufigste Muster: Statt mehrerer Konstruktoren mit unterschiedlichen Signaturen werden benannte Factory-Methoden im companion object verwendet.
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 in NetworkResult bietet eine Factory-Methode loading(), die eine Loading-Instanz mit dem richtigen generischen Typ erstellt. Ohne diese Methode müsste man eine Instanz direkt über Loading() erstellen, was die interne Implementierung offenlegt.
companion object wird häufig zum Speichern klassen-spezifischer Konstanten verwendet. Mit const val deklarierte Konstanten werden zur Kompilierzeit inline gesetzt, was eine Null-Overhead zur Laufzeit bietet.
class UserRepository {
companion object {
private const val TAG = "UserRepository"
private const val CACHE_SIZE = 100
private const val DEFAULT_PAGE_SIZE = 20
}
}
Häufig gestellte Fragen
Ein normales object ist ein vollwertiges Singleton, das unabhängig von der Klasse existiert. companion object ist ein object innerhalb einer Klasse, dessen Member über den Namen der äußeren Klasse aufgerufen werden. Im Bytecode wird ein companion object zu einer statischen verschachtelten Klasse, während ein normales object zu einer autonomen Singleton-Klasse wird.
Nein, companion object wird nicht von Unterklassen geerbt. Wenn Klasse B von Klasse A erbt, ruft B.method() nicht die Methode aus dem companion object von Klasse A auf — Sie müssen A.method() aufrufen. Dies entspricht dem Verhalten statischer Methoden in Java.
Standardmäßig — über ClassName.Companion.method(). Um es als statische Methode aufzurufen, fügen Sie @JvmStatic zur companion object-Methode hinzu. Für Felder verwenden Sie @JvmField oder deklarieren Sie sie mit const val für primitive Typen.
Die Kotlin-Entwickler haben sich entschieden, static zugunsten von companion object aufzugeben, für eine einheitliche Arbeit mit Objekten. static in Java verstößt gegen OOP-Prinzipien, da statische Methoden nicht an eine Instanz gebunden sind. companion object ist ein erstklassiges Objekt, das übergeben, mit Erweiterungsfunktionen erweitert und Schnittstellen implementieren kann.
Bei Verwendung von const val für primitive Typen und String — kein Overhead, der Wert wird in den Bytecode inline gesetzt. Bei Methoden gibt es keinen Overhead, es sei denn, die Methode ist inline. In den meisten Fällen erzeugt companion object keine messbaren Auswirkungen auf die Leistung. Verwenden Sie @JvmStatic nur für öffentliche APIs, die aus Java aufgerufen werden.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch