Erweiterungseigenschaften sind Erweiterungen für Klassen, die es ermöglichen, Getter und Setter hinzuzufügen, ohne einen Zustand (Backing Field) hinzufügen zu können. In Java gibt es diese Möglichkeit nicht, und das Äquivalent ist das Schreiben von Hilfsmethoden. Historisch gesehen musste man zur Erweiterung von Funktionalitäten statische Methoden oder Wrapper-Objekte verwenden.
Problem: Oft fehlen in externen Klassen die benötigten Eigenschaften. Man möchte die Klasse auf eine prägnante und sichere Weise erweitern, ohne die Kapselung zu verletzen.
Lösung: In Kotlin kann man eine Erweiterungseigenschaft deklarieren, die wie eine normale Eigenschaft aussieht, aber als Funktionen implementiert ist. Dies ermöglicht es, Typen zu erweitern, auf deren Quellcode wir keinen Zugriff haben, auf bequeme Weise.
Beispielcode:
val String.firstChar: Char get() = this[0] println("Kotlin".firstChar) // K
Wesentliche Merkmale:
Kann man einen Backing Field (Zustand) in einer Erweiterungseigenschaft hinzufügen?
Nein, die Erweiterungseigenschaft berechnet nur den Wert zur Laufzeit und kann keinen Zustand speichern.
Können Erweiterungseigenschaften Eigenschaften in abgeleiteten Klassen überschreiben?
Nein, Erweiterungseigenschaften (wie auch Erweiterungsfunktionen) sind im Grunde statisch: Sie können nicht überschrieben oder virtuell sein.
Wie wird die Erweiterungseigenschaft kompiliert und warum ist sie kein syntaktisches Äquivalent zu einer normalen Eigenschaft?
Die Erweiterungseigenschaft wird tatsächlich in eine statische Getter- (und/oder Setter-) Funktion kompiliert. Sie sind nicht Teil der Klassenentitäten und sind nur im Kontext der Datei sichtbar, in der sie deklariert sind.
Negativer Fall
Der Entwickler versuchte, eine Erweiterungseigenschaft für die Zustandsverwaltung von "Besuchtheit" in Standard-Views von Android hinzuzufügen:
var View.isVisited: Boolean get() = ... set(value) { ... } // Fehler: keine Speicherung
Vorteile:
Nachteile:
Positiver Fall
Eine Erweiterungseigenschaft für String wurde implementiert, um ein erweitertes Format zu erhalten:
val String.asTitle: String get() = this.replaceFirstChar { it.uppercase() }
Vorteile:
Nachteile: