在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Android/ Kotlin擴(kuò)展
Kotlin內(nèi)聯(lián)函數(shù)
Kotlin開發(fā)環(huán)境設(shè)置(Eclipse)
Kotlin調(diào)用Java代碼
Kotlin使用Ant
Kotlin編譯器插件
Kotlin相等性
Kotlin JavaScript模塊
編寫Kotlin代碼文檔
Kotlin返回和跳轉(zhuǎn)
Kotlin異常處理
Kotlin可見性修飾符
Kotlin委托
Kotlin委托屬性
Kotlin編碼約定/編碼風(fēng)格
Kotlin基礎(chǔ)語法
使用Kotlin進(jìn)行服務(wù)器端開發(fā)
Kotlin接口
Kotlin反射
Kotlin類型別名
Kotlin枚舉類
Kotlin當(dāng)前版本是多少?
Kotlin注解處理工具
Kotlin類型的檢查與轉(zhuǎn)換
Kotlin屬性和字段
Kotlin類型安全的構(gòu)建器
Kotlin相比Java語言有哪些優(yōu)點(diǎn)?
Kotlin JavaScript反射
Kotlin 是什么?
Kotlin泛型
Kotlin慣用語法
Kotlin與OSGi
Kotlin數(shù)據(jù)類型
Kotlin是面向?qū)ο筮€是函數(shù)式語言?
Kotlin動態(tài)類型
Kotlin協(xié)程
Kotlin操作符符重載
Kotlin使用Gradle
Kotlin密封類
Kotlin兼容性
Kotlin集合
Kotlin調(diào)用JavaScript
Kotlin null值安全
Kotlin函數(shù)
Kotlin開發(fā)環(huán)境設(shè)置(IntelliJ IDEA)
Kotlin嵌套類
Kotlin控制流程
Kotlin和Java語言比較
Kotlin 與 Java 語言兼容嗎?
Kotlin教程
Kotlin類和繼承
Kotlin對象表達(dá)式和對象聲明
JavaScript中調(diào)用Kotlin
Kotlin區(qū)間/范圍
Kotlin數(shù)據(jù)類
Kotlin lambda表達(dá)式
Kotlin是免費(fèi)的嗎?
Kotlin包
使用Kotlin進(jìn)行Android開發(fā)
在Java中調(diào)用Kotlin代碼
Kotlin this表達(dá)式
使用Kotlin進(jìn)行JavaScript開發(fā)
Kotlin擴(kuò)展
Kotlin解構(gòu)聲明
Kotlin注解
Kotlin使用Maven

Kotlin擴(kuò)展

Kotlin與C#和Go類似,提供了擴(kuò)展一個新功能的類,而不必繼承類或使用任何類型的設(shè)計模式,如Decorator。 這是通過稱為擴(kuò)展名的特殊聲明完成的。 Kotlin支持?jǐn)U展功能和擴(kuò)展屬性。

擴(kuò)展函數(shù)

要聲明一個擴(kuò)展函數(shù),需要用一個接收器類型,即被擴(kuò)展的類型來加上它的名字。 以下為MutableList <Int>添加swap函數(shù):

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}

擴(kuò)展函數(shù)中的this關(guān)鍵字對應(yīng)于接收器對象(在點(diǎn)之前傳遞的對象)。 現(xiàn)在,可以在任何MutableList <Int>上調(diào)用這樣一個函數(shù):

val l = mutableListOf(1, 2, 3)
l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l'

當(dāng)然,這個函數(shù)對于任何MutableList <T>是有意義的,可以將它通用化:

fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // 'this' corresponds to the list
    this[index1] = this[index2]
    this[index2] = tmp
}

在函數(shù)名稱之前聲明通用類型參數(shù),使其在接收器類型表達(dá)式中可用。 請參閱通用功能。

擴(kuò)展程序被靜態(tài)解析

擴(kuò)展不會實(shí)際修改它們擴(kuò)展的類。 通過定義擴(kuò)展名,不將新成員插入到類中,而只能使用這種類型的變量上的點(diǎn)符號來調(diào)用新的函數(shù)。

擴(kuò)展功能是靜態(tài)調(diào)度的,即它們不是接收器類型的虛擬機(jī)。 這意味著被調(diào)用的擴(kuò)展函數(shù)由調(diào)用該函數(shù)的表達(dá)式的類型決定,而不是在運(yùn)行時評估該表達(dá)式的結(jié)果的類型。 例如:

open class C

class D: C()

fun C.foo() = "c"

fun D.foo() = "d"

fun printFoo(c: C) {
    println(c.foo())
}

printFoo(D())

此示例將打印“c”,因?yàn)楸徽{(diào)用的擴(kuò)展函數(shù)僅取決于參數(shù)c(C類)的聲明類型。

該示例將打印“c”,因?yàn)轭惖?code>calleIf的擴(kuò)展函數(shù)具有成員函數(shù),并且定義了擴(kuò)展函數(shù),其具有相同的接收器類型,相同的名稱并且適用于給定的參數(shù)(該成員始終優(yōu)先)。 例如:

class C {
    fun foo() { println("member") }
}

fun C.foo() { println("extension") }

如果調(diào)用c類型的c.foo(),它將打印“member”而不是“extension”。

但是,擴(kuò)展函數(shù)可以重載具有相同名稱但不同簽名的成員函數(shù),這是完全可行的:

class C {
    fun foo() { println("member") }
}

fun C.foo(i: Int) { println("extension") }

C().foo(1)的調(diào)用將打印“extension”。

可接受Null的接收器

請注意,可以使用可空(null)接收器類型定義擴(kuò)展。 這樣的擴(kuò)展可以在一個對象變量上調(diào)用,即使它的值為null,并且可以在主體內(nèi)檢查this == null。 這樣就可以在Kotlin中調(diào)用toString(),而無需檢查null:檢查發(fā)生在擴(kuò)展函數(shù)內(nèi)。

fun Any?.toString(): String {
    if (this == null) return "null"
    // after the null check, 'this' is autocast to a non-null type, so the toString() below
    // resolves to the member function of the Any class
    return toString()
}

擴(kuò)展屬性

與函數(shù)類似,Kotlin支持?jǐn)U展屬性:

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

請注意,由于擴(kuò)展名實(shí)際上并不將成員插入到類中,因此擴(kuò)展屬性沒有有效的方式來添加后備字段。 這就是為什么不允許擴(kuò)展屬性的初始化器。 它們的行為只能通過明確提供getter / setter來定義。

val Foo.bar = 1 // error: initializers are not allowed for extension properties

伴隨對象擴(kuò)展

如果一個類定義了一個伴隨對象,那么還可以定義該對象的擴(kuò)展函數(shù)和屬性:

class MyClass {
    companion object { }  // will be called "Companion"
}

fun MyClass.Companion.foo() {
    // ...
}

就像伴隨對象的常規(guī)成員一樣,只能使用類名作為限定詞:

MyClass.foo()

擴(kuò)展范圍

大多數(shù)時候在頂層定義擴(kuò)展,即直接在包下:

package foo.bar

fun Baz.goo() { ... }

要在其聲明包之外使用這樣的擴(kuò)展,需要在調(diào)用時導(dǎo)入它:

package com.yiibai.usage

import foo.bar.goo // importing all extensions by name "goo"
                   // or
import foo.bar.*   // importing everything from "foo.bar"

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

有關(guān)詳細(xì)信息,請參閱導(dǎo)入。

聲明擴(kuò)展作為成員

在類中,可以為另一個類聲明擴(kuò)展名。 在這樣的擴(kuò)展中,有多個隱式接收器 - 可以在沒有限定符的情況下訪問對象成員。 聲明擴(kuò)展名的類的實(shí)例稱為調(diào)度接收方,擴(kuò)展方法的接收方型稱為擴(kuò)展接收方。

class D {
    fun bar() { ... }
}

class C {
    fun baz() { ... }

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

    fun caller(d: D) {
        d.foo()   // call the extension function
    }
}

在發(fā)送接收器的成員與分發(fā)接收器之間發(fā)生名稱沖突的情況下,分發(fā)接收器優(yōu)先。 要引用發(fā)送接收器的成員,可以使用合格的this語法

class C {
    fun D.foo() {
        toString()         // calls D.toString()
        this@C.toString()  // calls C.toString()
    }

聲明為成員的擴(kuò)展可以被聲明為在子類中打開(open)和覆蓋。 這意味著這種函數(shù)調(diào)度對于調(diào)度接收器類型是虛擬的,但是關(guān)于擴(kuò)展接收器類型是靜態(tài)的。

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()   // call the extension function
    }
}

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

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

C().caller(D())   // prints "D.foo in C"
C1().caller(D())  // prints "D.foo in C1" - dispatch receiver is resolved virtually
C().caller(D1())  // prints "D.foo in C" - extension receiver is resolved statically

動機(jī)

在Java中,我們習(xí)慣使用名為“*Utils”的類:FileUtils,StringUtils等。java.util.Collections也屬于這一類用法。 關(guān)于這些Utils類的令人不快的部分,如下代碼所示:

// Java
Collections.swap(list, Collections.binarySearch(list, Collections.max(otherList)), Collections.max(list))

這些類名總是要明確寫出來,但是可以使用靜態(tài)導(dǎo)入并得到:

// Java
swap(list, binarySearch(list, max(otherList)), max(list))

上面代碼是不是更好的一點(diǎn),但一般我們沒有或很少使用強(qiáng)大的IDE的代碼完成功能來完成。