Kotlin Erweiterungen

Kotlin kann die Eigenschaften und Methoden einer Klasse erweitern, ohne dass Vererbung oder das Decorator-Muster erforderlich sind.

Erweiterung ist ein statisches Verhalten und beeinflusst den Code der erweiterten Klasse selbst nicht.


Erweiterungsfunktionen

Erweiterungsfunktionen können vorhandenen Klassen neue Methoden hinzufügen, ohne die ursprüngliche Klasse zu verändern. Die Definitionsform einer Erweiterungsfunktion ist:

fun receiverType.functionName(params){
    body
}
  • receiverType: gibt den Empfänger der Funktion an, also das Objekt, das durch die Funktion erweitert wird
  • functionName: der Name der Erweiterungsfunktion
  • params: Parameter der Erweiterungsfunktion, können NULL sein

Das folgende Beispiel erweitert die User-Klasse:

class User(var name:String)

/**扩展函数**/
fun User.Print(){
    print("用户名 $name")
}

fun main(arg:Array<String>){
    var user = User("Example")
    user.Print()
}

Die Ausgabe des Beispiels ist:

用户名 Example

Der folgende Code gilt für MutableListum eine swap-Funktion hinzuzufügen:

// 扩展函数 swap,调换不同位置的值
fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1]     //  this 对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}

fun main(args: Array<String>) {

    val l = mutableListOf(1, 2, 3)
    // 位置 0 和 2 的值做了互换
    l.swap(0, 2) // 'swap()' 函数内的 'this' 将指向 'l' 的值

    println(l.toString())
}

Die Ausgabe des Beispiels ist:

[3, 2, 1]

Das Schlüsselwort this verweist auf das Empfängerobjekt (d. h. die Objektinstanz, die vor dem Punkt angegeben wird, wenn eine Erweiterungsfunktion aufgerufen wird).


Erweiterungsfunktionen werden statisch aufgelöst

Erweiterungsfunktionen werden statisch aufgelöst; sie sind keine virtuellen Member des Empfängertyps. Beim Aufruf einer Erweiterungsfunktion wird durch den Objektausdruck, der die Funktion aufruft, bestimmt, welche Funktion konkret aufgerufen wird, und nicht durch den dynamischen Typ:

open class C

class D: C()

fun C.foo() = "c"   // 扩展函数 foo

fun D.foo() = "d"   // 扩展函数 foo

fun printFoo(c: C) {
    println(c.foo())  // 类型是 C 类
}

fun main(arg:Array<String>){
    printFoo(D())
}

Die Ausgabe des Beispiels ist:

c

Wenn eine Erweiterungsfunktion und eine Memberfunktion identisch sind, wird bei Verwendung dieser Funktion die Memberfunktion bevorzugt verwendet.

class C {
    fun foo() { println("成员函数") }
}

fun C.foo() { println("扩展函数") }

fun main(arg:Array<String>){
    var c = C()
    c.foo()
}

Die Ausgabe des Beispiels ist:

Member function

Erweitern eines Null-Objekts

Innerhalb einer Erweiterungsfunktion können Sie this verwenden, um festzustellen, ob der Empfänger NULL ist. Auf diese Weise kann die Erweiterungsfunktion auch dann aufgerufen werden, wenn der Empfänger NULL ist. Zum Beispiel:

fun Any?.toString(): String {
    if (this == null) return "null"
    // 空检测之后,“this”会自动转换为非空类型,所以下面的 toString()
    // 解析为 Any 类的成员函数
    return toString()
}
fun main(arg:Array<String>){
    var t = null
    println(t.toString())
}

Die Ausgabe des Beispiels ist:

null

Erweiterungseigenschaften

Neben Funktionen unterstützt Kotlin auch das Erweitern von Eigenschaften durch Eigenschaften:

val <T> List<T>.lastIndex: Int
    get() = size - 1
 

Erweiterungseigenschaften können in Klassen oder Kotlin-Dateien definiert werden, aber nicht in Funktionen. Da Erweiterungseigenschaften kein Backing-Feld haben, können sie nicht initialisiert werden; sie können nur durch explizit bereitgestellte Getter/Setter definiert werden.

val Foo.bar = 1 // 错误:扩展属性不能有初始化器

Erweiterungseigenschaften können nur als val deklariert werden.


Erweiterungen für Companion-Objekte

Wenn eine Klasse ein Companion-Objekt definiert, können Sie auch Erweiterungsfunktionen und -eigenschaften für das Companion-Objekt definieren.

Ein Companion-Objekt wird in der Form "Class." aufgerufen. Erweiterungsfunktionen, die für ein Companion-Objekt deklariert sind, werden mit dem Klassennamen als Qualifizierer aufgerufen:

class MyClass {
    companion object { }  // 将被称为 "Companion"
}

fun MyClass.Companion.foo() {
    println("伴随对象的扩展函数")
}

val MyClass.Companion.no: Int
    get() = 10

fun main(args: Array<String>) {
    println("no:${MyClass.no}")
    MyClass.foo()
}

Die Ausgabe des Beispiels ist:

no:10
伴随对象的扩展函数

Gültigkeitsbereich von Erweiterungen

Üblicherweise werden Erweiterungsfunktionen oder -eigenschaften in einem Top-Level-Paket definiert:

package foo.bar

fun Baz.goo() { …… } 

Um eine Erweiterung von außerhalb des Pakets zu verwenden, in dem sie definiert ist, importieren Sie den Namen der Erweiterungsfunktion über import:

package com.example.usage

import foo.bar.goo // 导入所有名为 goo 的扩展
                   // 或者
import foo.bar.*   // 从 foo.bar 导入一切

fun usage(baz: Baz) {
    baz.goo()
}

Als Member deklarierte Erweiterungen

Innerhalb einer Klasse können Sie Erweiterungen für eine andere Klasse deklarieren.

In einer solchen Erweiterung gibt es mehrere implizite Empfänger. Die Instanz der Klasse, in der die Erweiterungsmethode definiert ist, wird Dispatch-Empfänger genannt, und die Instanz des Zieltyps der Erweiterungsmethode wird Erweiterungsempfänger genannt.

class D {
    fun bar() { println("D bar") }
}

class C {
    fun baz() { println("C baz") }

    fun D.foo() {
        bar()   // 调用 D.bar
        baz()   // 调用 C.baz
    }

    fun caller(d: D) {
        d.foo()   // 调用扩展函数
    }
}

fun main(args: Array<String>) {
    val c: C = C()
    val d: D = D()
    c.caller(d)

}

Die Ausgabe des Beispiels ist:

D bar
C baz

Innerhalb der Klasse C wird eine Erweiterung für die Klasse D erstellt. In diesem Fall wird C als Dispatch-Empfänger bezeichnet und D als Erweiterungsempfänger. Aus dem obigen Beispiel ist deutlich zu erkennen, dass Sie in einer Erweiterungsfunktion Member-Funktionen des Dispatch-Empfängers aufrufen können.

Wenn eine Funktion aufgerufen wird und sie sowohl im Dispatch-Empfänger als auch im Erweiterungsempfänger existiert, hat der Erweiterungsempfänger Vorrang. Um auf Member des Dispatch-Empfängers zu verweisen, können Sie die qualifizierte this-Syntax verwenden.

class D {
    fun bar() { println("D bar") }
}

class C {
    fun bar() { println("C bar") }  // 与 D 类 的 bar 同名

    fun D.foo() {
        bar()         // 调用 D.bar(),扩展接收者优先
        [email protected]()  // 调用 C.bar()
    }

    fun caller(d: D) {
        d.foo()   // 调用扩展函数
    }
}

fun main(args: Array<String>) {
    val c: C = C()
    val d: D = D()
    c.caller(d)

}

Die Ausgabe des Beispiels ist:

D bar
C bar

Als Member definierte Erweiterungsfunktionen können als open deklariert und in Unterklassen überschrieben werden. Das heißt, beim Dispatch-Vorgang solcher Erweiterungsfunktionen sind sie virtuell für den Dispatch-Empfänger, aber weiterhin statisch für den Erweiterungsempfänger.

open class D {
}

class D1 : D() {
}

open class C {
    open fun D.foo() {
        println("D.foo in C")
    }

    open fun D1.foo() {
        println("D1.foo in C")
    }

    fun caller(d: D) {
        d.foo()   // 调用扩展函数
    }
}

class C1 : C() {
    override fun D.foo() {
        println("D.foo in C1")
    }

    override fun D1.foo() {
        println("D1.foo in C1")
    }
}


fun main(args: Array<String>) {
    C().caller(D())   // 输出 "D.foo in C"
    C1().caller(D())  // 输出 "D.foo in C1" —— 分发接收者虚拟解析
    C().caller(D1())  // 输出 "D.foo in C" —— 扩展接收者静态解析

}

Die Ausgabe des Beispiels ist:

D.foo in C
D.foo in C1
D.foo in C
Andere Erweiterungen