Kotlin-Objektausdrücke und Objektdeklarationen

Kotlin verwendet Objektausdrücke und Objektdeklarationen, um ein Objekt einer Klasse mit geringfügigen Änderungen zu erstellen, ohne eine neue Unterklasse deklarieren zu müssen.


Objektausdrücke

Verwenden Sie einen Objektausdruck, um ein anonymes inneres Klassenobjekt zur Verwendung als Methodenparameter zu erstellen:

window.addMouseListener(object : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
        // ...
    }
    override fun mouseEntered(e: MouseEvent) {
        // ...
    }
})

Das Objekt kann von einer Basisklasse erben oder andere Schnittstellen implementieren:

open class A(x: Int) {
    public open val y: Int = x
}

interface B {……}

val ab: A = object : A(1), B {
    override val y = 15
}

Wenn der Supertyp einen Konstruktor hat, müssen Parameter an ihn übergeben werden. Mehrere Supertypen und Schnittstellen können durch Kommas getrennt werden.

Durch einen Objektausdruck kann man direkt ein Objekt erhalten, ohne eine Klassendefinition zu durchlaufen:

fun main(args: Array<String>) {
    val site = object {
        var name: String = "Example"
        var url: String = "www.example.com"
    }
    println(site.name)
    println(site.url)
}

Beachten Sie, dass anonyme Objekte nur als Typen in lokalen und privaten Gültigkeitsbereichen verwendet werden können. Wenn Sie ein anonymes Objekt als Rückgabetyp einer öffentlichen Funktion oder als Typ einer öffentlichen Eigenschaft verwenden, ist der tatsächliche Typ dieser Funktion oder Eigenschaft der vom anonymen Objekt deklarierte Supertyp oder Any, wenn kein Supertyp deklariert ist. Mitglieder, die im anonymen Objekt hinzugefügt wurden, sind nicht zugänglich.

class C {
    // 私有函数,所以其返回类型是匿名对象类型
    private fun foo() = object {
        val x: String = "x"
    }

    // 公有函数,所以其返回类型是 Any
    fun publicFoo() = object {
        val x: String = "x"
    }

    fun bar() {
        val x1 = foo().x        // 没问题
        val x2 = publicFoo().x  // 错误:未能解析的引用“x”
    }
}

In einem Objektausdruck kann bequem auf andere Variablen im Gültigkeitsbereich zugegriffen werden:

fun countClicks(window: JComponent) {
    var clickCount = 0
    var enterCount = 0

    window.addMouseListener(object : MouseAdapter() {
        override fun mouseClicked(e: MouseEvent) {
            clickCount++
        }

        override fun mouseEntered(e: MouseEvent) {
            enterCount++
        }
    })
    // ……
}

Objektdeklarationen

Kotlin verwendet das Schlüsselwort `object`, um ein Objekt zu deklarieren.

In Kotlin können wir mithilfe von Objektdeklarationen bequem ein Singleton erhalten.

object DataProviderManager {
    fun registerDataProvider(provider: DataProvider) {
        // ……
    }

    val allDataProviders: Collection<DataProvider>
        get() = // ……
}

Um auf dieses Objekt zu verweisen, können wir einfach seinen Namen verwenden:

DataProviderManager.registerDataProvider(……)

Natürlich können Sie auch eine Variable definieren, um dieses Objekt zu erhalten. Wenn Sie jedoch zwei verschiedene Variablen definieren, um dieses Objekt zu erhalten, werden Sie feststellen, dass Sie keine zwei verschiedenen Variablen erhalten können. Mit anderen Worten: Auf diese Weise erhalten wir ein Singleton.

var data1 = DataProviderManager
var data2 = DataProviderManager
data1.name = "test"
print("data1 name = ${data2.name}")  

Beispiel

Im folgenden Beispiel geben beide Objekte dieselbe URL-Adresse aus:

object Site {
    var url:String = ""
    val name: String = "Example"
}
fun main(args: Array<String>) {
    var s1 =  Site
    var s2 = Site
    s1.url = "www.example.com"
    println(s1.url)
    println(s2.url)
}

Das Ausgabeergebnis ist:

www.example.com
www.example.com

Objekte können Supertypen haben:

object DefaultListener : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) {
        // ……
    }

    override fun mouseEntered(e: MouseEvent) {
        // ……
    }
}

Im Gegensatz zu Objektausdrücken kann auf ein Objekt, das innerhalb einer anderen Klasse deklariert ist, nicht über eine Instanz der äußeren Klasse zugegriffen werden, sondern nur über den Klassennamen. Ebenso kann das Objekt nicht direkt auf die Methoden und Variablen der äußeren Klasse zugreifen.

class Site {
    var name = "Example"
    object DeskTop{
        var url = "www.example.com"
        fun showName(){
            print{"desk legs $name"} // 错误,不能访问到外部类的方法和变量
        }
    }
}
fun main(args: Array<String>) {
    var site = Site()
    site.DeskTop.url // 错误,不能通过外部类的实例访问到该对象
    Site.DeskTop.url // 正确
}

Begleitobjekte

Eine Objektdeklaration innerhalb einer Klasse kann mit dem Schlüsselwort `companion` gekennzeichnet werden, sodass sie der äußeren Klasse zugeordnet ist und wir direkt über die äußere Klasse auf die internen Elemente des Objekts zugreifen können.

class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
    }
}

val instance = MyClass.create()   // 访问到对象的内部元素

Wir können den Objektnamen des Objekts weglassen und dann `Companion` verwenden, um den Namen zu ersetzen, der deklariert werden muss:

class MyClass {
    companion object {
    }
}

val x = MyClass.Companion

Hinweis:Eine Klasse kann nur ein intern zugeordnetes Objekt deklarieren, d. h. das Schlüsselwort `companion` kann nur einmal verwendet werden.

Die Mitglieder eines Companion-Objekts sehen wie statische Mitglieder in anderen Sprachen aus, aber zur Laufzeit sind sie immer noch Instanzmitglieder eines echten Objekts. Zum Beispiel kann es auch Schnittstellen implementieren:

interface Factory<T> {
    fun create(): T
}


class MyClass {
    companion object : Factory<MyClass> {
        override fun create(): MyClass = MyClass()
    }
}

Semantische Unterschiede zwischen Objektausdrücken und Objektdeklarationen

Es gibt einen wichtigen semantischen Unterschied zwischen Objektausdrücken und Objektdeklarationen:

  • Objektausdrücke werden sofort dort ausgeführt, wo sie verwendet werden.

  • Objektdeklarationen werden bei erstem Zugriff verzögert initialisiert.

  • Die Initialisierung eines Companion-Objekts erfolgt beim Laden (Auflösen) der entsprechenden Klasse und entspricht der Semantik von Java-Statik-Initialisierern.

Andere Erweiterungen