反射

KClass

kt 中 Classs 类。其对应的是 java.lang.Class

下面所使用的 Test 类定义如下:

class Test {
    var name: String = ""
    fun test(sex: String, age: Int) = "$sex+$age"
}
  1. 通过 MyClass::class 获取指定类对应的 KClass 对象。就像在 java 中通过 MyClass.class 获取指定类的 Class 对象一样。

    fun main(args: Array) {
        val t = Test()
        val clazz:KClass = Test::class  // 返回一个 KClass 对象
    }
    
  2. 通过 对象.javaClass.kotlin 获取指定实例对应的 KClass 实例。其中 对象.javaClass 可以获取指定类的 java Class 实例。

    fun main(args: Array) {
        val t = Test()
        println(t.javaClass is Class) // true
    }
    
  3. KClass 与 Class 转换:

    • 对象.javaClass 得到 Class 对象,再 .kotlin 得到 KClass 对象

    • 类名::class 得到 KClass 对象,再 .java 得到 Class 对象。

    • 对象::class 得到 KClass 对象,再 .java 得到 Class 对象。


属性

KClass 属性如下:

属性 含义
memberProperties 所有属性,含从父类中继承的
annotations 获取元素上的所有注解。定义于 KAnnotatedElement 中
createInstance() 方法。通过 KClass 创建一个实例
objectInstance 如果类是单例的,则存储其唯一实例。否则为空
object Test {
    val name = "naan"
    fun test() = println("tesss")
}

Test::class.objectInstance 其不为空,如果将 object 换成 class ,则值为空


KCallback 与 KFunction,KProperty

KCallback 是函数和属性的超接口。其内部定义有 call 方法,调用该方法就相当于调用函数或者属性的 getter ;KFunction 是 KCallback 的子类,它是函数的接口;KProperty 是 KCallback 的子类,它是属性的接口。

属性 含义
name 获取方法或属性名
parameters 参数列表
  1. 三者接收的第一个参数均为执行该方法所需要的对象。就像 java 中执行某个反射方法时,需要为该方法指定一个执行对象。

  2. KFunction 的泛型说明:除最后一个泛型外,其余的均为调用其 invoke 方法时需要传递参数类型,最后一个泛型为 invoke 方法返回值类型。也即对应方法的参数类型列表和返回值类型。

  3. 使用 成员引用函数时,返回的是一个 KFunction 实例。调用其 invoke 就相当于执行该方法:

反射_第1张图片
KFunction 参数,返回值
  1. 使用 成员引用属性时,返回的是一个 KProperty 实例。调用其 get 相当于调用该实例的 getter 方法:

    反射_第2张图片
    KProperty
  2. KProperty 泛型说明:第一个参数表示接收者类型,第二个参数表示属性类型。

  3. 对于 var 修饰的变量,通过 KProperty 定义 set 方法修改其值。但对不可变变量,没有 set 方法。

  4. parameters 返回的参数列表中,第一个参数为 receiver,表示执行当前方法的实例。

继承关系

反射_第3张图片
继承关系
  1. 因为所有的声明都可以被注解(KAnnotatedElement 类的作用),所以 KClasss,KCallback,KParameter 都继承于 KAnnotatedElement。

  2. KProperty 只有 get 方法,用于 val 声明的变量

  3. KMutableProperty 有 set 方法,用于 var 声明的变更。

  4. 两者内部有 getter/setter 接口,用于获取相应属性的 getter/setter 方法。getter/setter 接口都继承于 KFunction,因此可以把他们当作函数调用。

fun main(args: Array) {
    val test = Test::name
    val t = Test()
    println(test.getter.invoke(t))
    test.setter.invoke(t,"yyy")
    println(test.getter.invoke(t))
}

构造函数

通过 KClass#constructors 可以获取所有的构造函数。

构造函数也是函数,因此每一个构造函数都是 KFunction 的子类。故而可以调用 call 方法创建实例

fun main(args: Array) {
    val kclzzz = Test::class
    val t = kclzzz.constructors
    t.forEach {
        val i = it.call("name", 20)
        println(i)
    }
}
data class Test(val name: String, var age: Int = 10)

但 call 方法不支持默认参数,即上面创建实例时,即使 Test 类中 age 已经指定了默认值 10 ,调用 call() 时也必须传入一个对应的实参。

callBy

callBy 定义在 KCallback 类中。

与 call() 方法相比,它接收一个 map —— map 存储了方法形参与其实参之间的对应关系。

  1. 如果 map 缺少形参,则该形参会使用默认值,如果有默认值的话

2.形参的顺序不必和方法中一样

  1. map 中值的类型需要跟构造方法中参数类型一致

KParameter

方法参数

  1. name 表示参数名

  2. type 表示参数类型

  3. isOptional 表示该参数是否有默认值。true 表示有默认值,false 没有。

你可能感兴趣的:(反射)