反射
反射是一系列语言和库的特性,允许在运行时获取你代码结构。 把函数和属性作为语言的一等公民,反射它们(如获名称或者属性类型或者 方法)和使用函数式编程或反应是编程风格很像。
在Java平台,使用反射特性所需的运行时组件作为一个单独的 Jar 文件(
kotlin-reflect.jar
).这样做减小了不使用反射的应用程序库的大小. 如果你确实要使用反射,请确保该文件被添加到了项目路径.
类引用
最基本的反射特性就是得到运行时的类引用。要获取引 用并使之成为静态类可以使用字面类语法:
val c = MyClass::class
引用是KClass类型.你可以使用KClass.properties
和KClass.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)