Kotlin const vs val: Was ist der Unterschied und was wählen?
\n\nSie schreiben Code in Kotlin und fragen sich plötzlich: "Was ist eigentlich der Unterschied zwischen const und val? Beide sind doch scheinbar unveränderlich?". Eine ausgezeichnete Frage! Dieser Punkt verwirrt selbst erfahrene Entwickler, die von Java oder anderen Sprachen wechseln. Kein Wunder, dass das Thema „What is the difference between "const" and "val"?“ auf Stack Overflow tausende Aufrufe erhält. Heute werden wir diese Frage ein für alle Mal klären, die Theorie Schritt für Schritt aufschlüsseln und alles mit lebendigen Codebeispielen untermauern.
Bereit? Los geht's!
\n\nKurze Einführung: Was ist val?
\n\nBeginnen wir mit dem Einfachsten. val (vom Wort value – Wert) ist eine unveränderliche Referenz. Sie können ihr einmal einen Wert zuweisen und ihn danach nie mehr ändern. Kommt Ihnen bekannt vor? Ja, es ist das Äquivalent zu final in Java oder readonly in C#.
val name: String = "Alice"\nname = "Bob" // Compiler-Fehler! Val cannot be reassigned\n\nAber es gibt eine wichtige Nuance: val garantiert, dass sich die Referenz nicht ändert, aber nicht die Unveränderlichkeit des Objekts selbst. Wenn Sie val mit einer veränderlichen Liste (MutableList) verwenden, können Sie dennoch Elemente hinzufügen und entfernen.
val numbers = mutableListOf(1, 2, 3)\nnumbers.add(4) // Funktioniert!\n// numbers = mutableListOf(5, 6) // Fehler! Referenz kann nicht neu zugewiesen werden\n\nval kann sowohl bei der Deklaration als auch später im Code (z.B. im Konstruktor oder im init-Block) initialisiert werden. Sein Wert wird zur Laufzeit des Programms (runtime) berechnet.
Und was ist const? Der strenge Wächter der Kompilierzeit
\n\nconst ist der strengere Bruder von val. Es ist ebenfalls unveränderlich, aber mit einer Superkraft: Der Wert muss zum Zeitpunkt der Kompilierung (compile-time) bekannt sein. Mit anderen Worten, es ist eine echte Konstante, die der Compiler direkt in den Code einfügen kann, wie eine eingebaute Konstante.
const hat strenge Regeln:
- \n
- Kann nur auf Dateiebene (außerhalb einer Klasse) oder innerhalb eines
object/companion objectdeklariert werden. \n - Muss von einem primitiven Typ oder vom Typ
Stringsein. \n - Darf nicht das Ergebnis eines Funktionsaufrufs oder einer Berechnung sein – nur ein Literal oder eine andere Konstante. \n
// Richtig\nconst val PI = 3.14159\nconst val APP_NAME = "MyApp"\n\n// Falsch\nconst val currentTime = System.currentTimeMillis() // Fehler! Wert ist zum Zeitpunkt der Kompilierung nicht bekannt\nconst val userName = getName() // Fehler! Funktionsaufruf nicht zulässig\n\nDie Hauptunterschiede: const vs val in einer Tabelle
\n\nZur Veranschaulichung hier eine Vergleichstabelle:
\n\n| Kriterium | \nconst val | \nval | \n
|---|---|---|
| Initialisierungszeitpunkt | \nZum Zeitpunkt der Kompilierung | \nZum Zeitpunkt der Ausführung | \n
| Wo deklarierbar | \nTop-Level, object, companion object | \nÜberall (innerhalb einer Klasse, Funktion, Konstruktor) | \n
| Datentypen | \nNur primitive Typen und String | \nBeliebige Typen (einschließlich Objekte, Listen) | \n
| Leistung | \nMaximal (Inlining) | \nStandard | \n
| Verwendung in Annotationen | \nJa | \nNein | \n
Praktisches Beispiel: Annotationen und Leistung
\n\nEine der