Eigenschaften
Eine Eigenschaft ist ein
varoderval, das Teil einer Klasse ist.
Das Definieren einer Eigenschaft beibehält den Zustand innerhalb einer Klasse. Das Beibehalten des Zustands ist der Hauptmotivationsgrund, eine Klasse zu erstellen, anstatt nur eine oder mehrere eigenständige Funktionen zu schreiben.
Eine var-Eigenschaft kann neu zugewiesen werden, während eine val-Eigenschaft dies nicht kann. Jedes Objekt erhält seinen eigenen Speicher für Eigenschaften:
// Properties/Cup.kt
class Cup {
var percentFull = 0
}
fun main() {
val c1 = Cup()
c1.percentFull = 50
val c2 = Cup()
c2.percentFull = 100
println(c1.percentFull)
println(c2.percentFull)
}
/* Output:
50
100
*/
Das Definieren eines var oder val innerhalb einer Klasse sieht genauso aus wie das Definieren innerhalb einer Funktion. Allerdings wird das var oder val Teil dieser Klasse, und Sie müssen darauf verweisen, indem Sie das Objekt mit Punktnotation angeben, wobei Sie einen Punkt zwischen das Objekt und den Namen der Eigenschaft setzen. Sie können die Punktnotation bei jedem Verweis auf percentFull sehen.
Die Eigenschaft percentFull repräsentiert den Zustand des entsprechenden Cup-Objekts. c1.percentFull und c2.percentFull enthalten unterschiedliche Werte, was zeigt, dass jedes Objekt über seinen eigenen Speicherplatz verfügt.
Eine Mitgliedsfunktion kann auf eine Eigenschaft innerhalb ihres Objekts verweisen, ohne die Punktnotation zu verwenden (das heißt, ohne sie zu qualifizieren):
// Properties/Cup2.kt
class Cup2 {
var percentFull = 0
val max = 100
fun add(increase: Int): Int {
percentFull += increase
if (percentFull > max)
percentFull = max
return percentFull
}
}
fun main() {
val cup = Cup2()
cup.add(50)
println(cup.percentFull)
cup.add(70)
println(cup.percentFull)
}
/* Output:
50
100
*/
Die add()-Mitgliedsfunktion versucht, increase zu percentFull hinzuzufügen, stellt jedoch sicher, dass es nicht über 100 % hinausgeht.
Eigenschaften und Mitgliedsfunktionen müssen von außerhalb einer Klasse qualifiziert werden.
Man kann Eigenschaften auf oberster Ebene definieren:
// Properties/TopLevelProperty.kt
val constant = 42
var counter = 0
fun inc() {
counter++
}
Die Definition eines val auf oberster Ebene ist sicher, da es nicht verändert werden kann. Die Definition einer veränderbaren (var) Eigenschaft auf oberster Ebene wird jedoch als Antimuster angesehen. Wenn Ihr Programm komplizierter wird, wird es schwieriger, den gemeinsamen veränderbaren Zustand korrekt zu verstehen. Wenn jeder in Ihrem Code Zugriff auf den var Zähler hat, können Sie nicht garantieren, dass er korrekt verändert wird: Während inc() den Zähler um eins erhöht, könnte ein anderer Teil des Programms den Zähler um zehn verringern, was zu schwer nachvollziehbaren Fehlern führt. Es ist am besten, veränderbaren Zustand innerhalb einer Klasse zu schützen. In Sichtbarkeit einschränken wird gezeigt, wie man ihn wirklich verstecken kann.
Zu sagen, dass vars verändert werden können, während vals dies nicht können, ist eine Vereinfachung. Als Analogie können Sie ein Haus als val betrachten und ein Sofa im Haus als var. Sie können das Sofa verändern, weil es ein var ist. Sie können jedoch das Haus nicht neu zuweisen, da es ein val ist:
// Properties/ChangingAVal.kt
class House {
var sofa: String = ""
}
fun main() {
val house = House()
house.sofa = "Simple sleeper sofa: $89.00"
println(house.sofa)
house.sofa = "New leather sofa: $3,099.00"
println(house.sofa)
// Cannot reassign the val to a new House:
// house = House()
}
/* Output:
Simple sleeper sofa: $89.00
New leather sofa: $3,099.00
*/
Obwohl house ein val ist, kann sein Objekt modifiziert werden, weil sofa in
class House ein var ist. Die Definition von house als val verhindert nur, dass es einem neuen Objekt neu zugewiesen wird.
Wenn wir eine Eigenschaft als val definieren, kann sie nicht neu zugewiesen werden:
// Properties/AnUnchangingVar.kt
class Sofa {
val cover: String = "Loveseat cover"
}
fun main() {
var sofa = Sofa()
// Not allowed:
// sofa.cover = "New cover"
// Reassigning a var:
sofa = Sofa()
}
Auch wenn sofa eine var ist, kann sein Objekt nicht modifiziert werden, weil cover in
class Sofa ein val ist. sofa kann jedoch einem neuen Objekt zugewiesen werden.
Wir haben über Bezeichner wie house und sofa gesprochen, als wären sie Objekte.
Tatsächlich sind sie Referenzen auf Objekte. Eine Möglichkeit, dies zu sehen, ist zu beobachten,
dass zwei Bezeichner auf dasselbe Objekt verweisen können:
// Properties/References.kt
class Kitchen {
var table: String = "Round table"
}
fun main() {
val kitchen1 = Kitchen()
val kitchen2 = kitchen1
println("kitchen1: ${kitchen1.table}")
println("kitchen2: ${kitchen2.table}")
kitchen1.table = "Square table"
println("kitchen1: ${kitchen1.table}")
println("kitchen2: ${kitchen2.table}")
}
/* Output:
kitchen1: Round table
kitchen2: Round table
kitchen1: Square table
kitchen2: Square table
*/
Wenn kitchen1 table verändert, sieht kitchen2 die Änderung.
kitchen1.table und kitchen2.table zeigen die gleiche Ausgabe.
Denken Sie daran, dass var und val Referenzen anstelle von Objekten steuern. Ein var ermöglicht es Ihnen, eine Referenz auf ein anderes Objekt neu zu binden, während ein val dies verhindert.
Veränderlichkeit bedeutet, dass ein Objekt seinen Zustand ändern kann. In den obigen Beispielen definieren class House und class Kitchen veränderliche Objekte, während class Sofa unveränderliche Objekte definiert.
Übungen und Lösungen finden Sie unter www.AtomicKotlin.com.