Edit Page

反射

反射是一系列语言和库的特性,允许在运行时获取你代码结构。 把函数和属性作为语言的一等公民,反射它们(如获名称或者属性类型或者 方法)和使用函数式编程或反应是编程风格很像。

在Java平台,使用反射特性所需的运行时组件作为一个单独的 Jar 文件(kotlin-reflect.jar).这样做减小了不使用反射的应用程序库的大小. 如果你确实要使用反射,请确保该文件被添加到了项目路径.

类引用

最基本的反射特性就是得到运行时的类引用。要获取引 用并使之成为静态类可以使用字面类语法:

val c = MyClass::class

引用是KClass类型.你可以使用KClass.propertiesKClass.extensionProperties来获得类和父类所有属性引用的列表。

注意Kotlin类引用不完全与Java类引用一致.查看Java interop section 详细信息。

函数引用

我们有一个像下面这样的函数声明:

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

我们可以直接调用(isOdd(5)), 也可以把它作为一个值传给其他函数. 我们使用::操作符实现:

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

这里 ::isOdd是一个函数类型的值 (Int) -> Boolean.

:: can be used with overloaded functions when the expected type is known from the context. For example:

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)) // refers to isOdd(x: Int)

Alternatively, you can provide the necessary context by storing the method reference in a variable with an explicitly specified type:

val predicate: (String) -> Boolean = ::isOdd   // refers to isOdd(x: String)

如果我们需要使用类成员或者一个扩展方法,它必须是有权访问的, 例如String::toCharArray带着一个String: String.() -> CharArray类型扩展函数.

例子: 函数组合

考量以下方法:

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

它返回一个由俩个传递进去的函数的组合。 现在你可以把它用在可调用的引用上了:

fun length(s: String) = s.length

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

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

属性引用

我们同样可以用::操作符来访问Kotlin中的顶级类的属性:

var x = 1

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

表达式::x推断为KProperty<Int>类型的属性对象,它允许我们 使用get()函数来读它的值或者使用name属性来得到它的值。更多请 查看docs on the KProperty class.

对于可变属性,例如var y = 1, ::y返回值类型是KMutableProperty<Int>, 它有一个set()方法.

A property reference can be used where a function with no parameters is expected:

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

To access a property that is a member of a class, we qualify it:

class A(val p: Int)

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

对于扩展属性:

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

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

与Java反射调用

在 java 平台上,标准库包括反射类的扩展,提供了到 java 反射 对象的映射(参看 kotlin.reflect.jvm包)。 比如,想找到一个备用字段或者 java getter 方法,你可以这样写:

import kotlin.reflect.jvm.*

class A(val p: Int)

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

To get the Kotlin class corresponding to a Java class, use the .kotlin extension property:

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

构造函数引用

构造函数可以像属性和方法那样引用. 它们可以使用在任何一个函数类型的对象的地方, 期望得到相同参数的构造函数,并返回一个适当类型的对象. 构造函数使用::操作符加类名引用.考虑如下函数, 需要一个无参数函数返回类型是Foo:

class Foo

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

Using ::Foo, the zero-argument constructor of the class Foo, 我们可以简单的这样使用:

function(::Foo)