鍍金池/ 教程/ Android/ Kotlin反射
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編碼約定/編碼風格
Kotlin基礎(chǔ)語法
使用Kotlin進行服務(wù)器端開發(fā)
Kotlin接口
Kotlin反射
Kotlin類型別名
Kotlin枚舉類
Kotlin當前版本是多少?
Kotlin注解處理工具
Kotlin類型的檢查與轉(zhuǎn)換
Kotlin屬性和字段
Kotlin類型安全的構(gòu)建器
Kotlin相比Java語言有哪些優(yōu)點?
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對象表達式和對象聲明
JavaScript中調(diào)用Kotlin
Kotlin區(qū)間/范圍
Kotlin數(shù)據(jù)類
Kotlin lambda表達式
Kotlin是免費的嗎?
Kotlin包
使用Kotlin進行Android開發(fā)
在Java中調(diào)用Kotlin代碼
Kotlin this表達式
使用Kotlin進行JavaScript開發(fā)
Kotlin擴展
Kotlin解構(gòu)聲明
Kotlin注解
Kotlin使用Maven

Kotlin反射

反射是這樣的一組語言和庫功能,它允許在運行時自省你的程序的結(jié)構(gòu)。
Kotlin 讓語言中的函數(shù)和屬性做為一等公民、并對其自省(即在運行時獲悉
一個名稱或者一個屬性或函數(shù)的類型)與簡單地使用函數(shù)式或響應(yīng)式風格緊密相關(guān)。

在 Java 平臺上,使用反射功能所需的運行時組件作為單獨的
JAR 文件(kotlin-reflect.jar)分發(fā)。這樣做是為了減少不使用反射功能的應(yīng)用程序所需的
運行時庫的大小。如果你需要使用反射,請確保該 .jar文件添加到項目的
classpath 中。

類引用

最基本的反射功能是獲取 Kotlin 類的運行時引用。要獲取對
靜態(tài)已知的 Kotlin 類的引用,可以使用 類字面值 語法:

val c = MyClass::class

該引用是 KClass 類型的值。

請注意,Kotlin 類引用與 Java 類引用不同。要獲得 Java 類引用,
請在 KClass 實例上使用 .java 屬性。

綁定的類引用(自 1.1 起)

通過使用對象作為接收者,可以用相同的 ::class 語法獲取指定對象的類的引用:

val widget: Widget = ……
assert(widget is GoodWidget) { "Bad widget: ${widget::class.qualifiedName}" }

你可以獲取對象的精確類的引用,例如 GoodWidgetBadWidget,盡管接收者表達式的類型是 Widget。

函數(shù)引用

當我們有一個命名函數(shù)聲明如下:

fun isOdd(x: Int) = x % 2 != 0

我們可以很容易地直接調(diào)用它(isOdd(5)),但是我們也可以把它作為一個值傳遞。例如傳給另一個函數(shù)。
為此,我們使用 :: 操作符:

val numbers = listOf(1, 2, 3)
println(numbers.filter(::isOdd)) // 輸出 [1, 3]

這里 ::isOdd 是函數(shù)類型 (Int) -> Boolean 的一個值。

當上下文中已知函數(shù)期望的類型時,:: 可以用于重載函數(shù)。
例如:

fun isOdd(x: Int) = x % 2 != 0
fun isOdd(s: String) = s == "brillig" || s == "slithy" || s == "tove"

val numbers = listOf(1, 2, 3)
println(numbers.filter(::isOdd)) // 引用到 isOdd(x: Int)

或者,你可以通過將方法引用存儲在具有顯式指定類型的變量中來提供必要的上下文:

val predicate: (String) -> Boolean = ::isOdd   // 引用到 isOdd(x: String)

如果我們需要使用類的成員函數(shù)或擴展函數(shù),它需要是限定的。
例如 String::toCharArray 為類型 String 提供了一個擴展函數(shù):String.() -> CharArray

示例:函數(shù)組合

考慮以下函數(shù):

fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C {
    return { x -> f(g(x)) }
}

它返回一個傳給它的兩個函數(shù)的組合:compose(f, g) = f(g(*))。
現(xiàn)在,你可以將其應(yīng)用于可調(diào)用引用:

fun length(s: String) = s.length

val oddLength = compose(::isOdd, ::length)
val strings = listOf("a", "ab", "abc")

println(strings.filter(oddLength)) // 輸出 "[a, abc]"

屬性引用

要把屬性作為 Kotlin中 的一等對象來訪問,我們也可以使用 :: 運算符:

var x = 1

fun main(args: Array<String>) {
    println(::x.get()) // 輸出 "1"
    ::x.set(2)
    println(x)         // 輸出 "2"
}

表達式 ::x 求值為 KProperty<Int> 類型的屬性對象,它允許我們使用
get() 讀取它的值,或者使用 name 屬性來獲取屬性名。更多信息請參見
關(guān)于 KProperty 類的文檔

對于可變屬性,例如 var y = 1::y 返回 KMutableProperty<Int> 類型的一個值,
該類型有一個 set() 方法。

屬性引用可以用在不需要參數(shù)的函數(shù)處:

val strs = listOf("a", "bc", "def")
println(strs.map(String::length)) // 輸出 [1, 2, 3]

要訪問屬于類的成員的屬性,我們這樣限定它:

class A(val p: Int)

fun main(args: Array<String>) {
    val prop = A::p
    println(prop.get(A(1))) // 輸出 "1"
}

對于擴展屬性:

val String.lastChar: Char
    get() = this[length - 1]

fun main(args: Array<String>) {
    println(String::lastChar.get("abc")) // 輸出 "c"
}

與 Java 反射的互操作性

在Java平臺上,標準庫包含反射類的擴展,它提供了與 Java
反射對象之間映射(參見 kotlin.reflect.jvm 包)。
例如,要查找一個用作 Kotlin 屬性 getter 的 幕后字段或 Java方法,可以這樣寫:

import kotlin.reflect.jvm.*

class A(val p: Int)

fun main(args: Array<String>) {
    println(A::p.javaGetter) // 輸出 "public final int A.getP()"
    println(A::p.javaField)  // 輸出 "private final int A.p"
}

要獲得對應(yīng)于 Java 類的 Kotlin 類,請使用 .kotlin 擴展屬性:

fun getKClass(o: Any): KClass<Any> = o.javaClass.kotlin

構(gòu)造函數(shù)引用

構(gòu)造函數(shù)可以像方法和屬性那樣引用。他們可以用于期待這樣的函數(shù)類型對象的任何
地方:它與該構(gòu)造函數(shù)接受相同參數(shù)并且返回相應(yīng)類型的對象。
通過使用 :: 操作符并添加類名來引用構(gòu)造函數(shù)??紤]下面的函數(shù),
它期待一個無參并返回 Foo 類型的函數(shù)參數(shù):

class Foo

fun function(factory: () -> Foo) {
    val x: Foo = factory()
}

使用 ::Foo,類 Foo 的零參數(shù)構(gòu)造函數(shù),我們可以這樣簡單地調(diào)用它:

function(::Foo)

綁定的函數(shù)與屬性引用(自 1.1 起)

你可以引用特定對象的實例方法。

val numberRegex = "\\d+".toRegex()
println(numberRegex.matches("29")) // 輸出“true”

val isNumber = numberRegex::matches
println(isNumber("29")) // 輸出“true”

取代直接調(diào)用方法 matches 的是我們存儲其引用。
這樣的引用會綁定到其接收者上。
它可以直接調(diào)用(如上例所示)或者用于任何期待一個函數(shù)類型表達式的時候:

val strings = listOf("abc", "124", "a70")
println(strings.filter(numberRegex::matches)) // 輸出“[124]”

比較綁定的類型和相應(yīng)的未綁定類型的引用。
綁定的可調(diào)用引用有其接收者“附加”到其上,因此接收者的類型不再是參數(shù):

val isNumber: (CharSequence) -> Boolean = numberRegex::matches

val matches: (Regex, CharSequence) -> Boolean = Regex::matches

屬性引用也可以綁定:

val prop = "abc"::length
println(prop.get())   // 輸出“3”