• 【Kotlin精简】第6章 反射


    1 反射简介

    反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性。

    1.1 Kotlin反射

    在这里插入图片描述
    在这里插入图片描述
    我们对比Kotlin和Java的反射类图

    1.1.1 Kotlin反射常用的数据结构

    数据结构概念及使用说明
    KType描述未擦除的类型或泛型参数等,例如 Map;可通过 typeof 或者以下类型获取对应的父类、属性、函数参数等
    KClass描述对象的实际类型,不包含泛型参数,例如Map可通过对象、类型名直接获得
    KProperty描述属性,可通过属性引用、属性所在类的 KClass 获取
    KFunction描述函数,可通过函数引用、函数所在类的 KClass 获取

    1.2 对比Java反射

    在这里插入图片描述
    在这里插入图片描述

    1.2.1 Kotlin与Java 反射优缺点

    1. Java 反射
      优点:无需引入额外依赖,首次使用速度相对较快
      缺点: 无法访问 Kotlin 语法特性,需对 Kotlin 生成的字节码足够了解

    2. Kotlin 反射
      优点: 支持访问 Kotlin 几乎所有特性,API 设计更友好
      缺点:引入 Kotin 反射库(2.5MB,编译后 400KB),首次调用慢

    1.3 反射用途

    1. 在运行时判断任意一个**对象所属的类**
    2. 在运行时构造任意一个**类的对象**
    3. 在运行时判断任意一个**类所具有的成员变量和方法**
    4. 在运行时调用任意一个**对象的方法**

    2 Kotlin反射

    2.1 反射使用

    Kotlin 的反射需要集成 org.jetbrains.kotlin:kotlin-reflect 仓库,版本保持与 Kotlin 一致。

    implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
    
    • 1

    Kotlin中,字节码对应的类是kotlin.reflect.KClass,因为Kotlin百分之百兼容Java,所以Kotlin中可以使用Java中的反射,但是由于Kotlin中字节码.class对应的是KClass类,所以如果想要使用Java中的反射,需要首先获取Class的实例,在Kotlin中可以通过以下两种方式来获取Class实例。

    //1.通过实例.javaClass
    var hello = HelloWorld()
    hello.javaClass
    
     //2.通过类Kclass类的.java属性
    HelloWorld::class.java
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    获取了Class实例,就可以调用上面介绍的方法,获取各种在Java中定义的类的信息了。

    当然Kotlin中除了可以使用Java中的反射以外,还可以使用Kotlin中声明的一些方法,当然同Java中反射一样,想要使用这些方法,先要获取Kclass对象,在Kotlin中可以通过以下两种方式获取KClass实例。

     //1.通过类::class的方式获取Kclass实例
    val clazz1: KClass<*> = HelloWorld::class
    //2.通过实例.javaClass.kotlin获取Kclass实例
    var hello = HelloWorld()
    val clazz2 = hello.javaClass.kotlin
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.2 常用API

    2.2.1 构造函数Constructor

    //返回这个类的所有构造器
    public val constructors: Collection<KFunction<T>>
    
    • 1
    • 2

    2.2.2 成员变量和成员函数

     //返回类可访问的所有函数和属性,包括继承自基类的,但是不包括构造器
     override val members: Collection<KCallable<*>>
     //返回类声明的所有函数
     val KClass<*>.declaredFunctions: Collection<KFunction<*>>
     //返回类的扩展函数
     val KClass<*>.declaredMemberExtensionFunctions: Collection<KFunction<*>>
     //返回类的扩展属性
     val <T : Any> KClass<T>.declaredMemberExtensionProperties: Collection<KProperty2<T, *, *>>
     //返回类自身声明的成员函数
     val KClass<*>.declaredMemberFunctions: Collection<KFunction<*>>
     //返回类自身声明的成员变量(属性)
     val <T : Any> KClass<T>.declaredMemberProperties: Collection<KProperty1<T, *>>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.2.3 类相关信息

    //1.返回类的名字
    public val simpleName: String?
    //2.返回类的全包名
    public val qualifiedName: String?
    //3.如果这个类声明为object,则返回其实例,否则返回null
    public val objectInstance: T?
    //4.返回类的可见性
    @SinceKotlin("1.1")
    public val visibility: KVisibility?
    //5.判断类是否为final类(在Kotlin中,类默认是final的,除非这个类声明为open或者abstract)
    @SinceKotlin("1.1")
    public val isFinal: Boolean
    //6.判断类是否是open的(abstract类也是open的),表示这个类可以被继承
    @SinceKotlin("1.1")
    public val isOpen: Boolean
    //7.判断类是否为抽象类
    @SinceKotlin("1.1")
    public val isAbstract: Boolean
    //8.判断类是否为密封类,密封类:用sealed修饰,其子类只能在其内部定义
    @SinceKotlin("1.1")
    public val isSealed: Boolean
    //9.判断类是否为data类
    @SinceKotlin("1.1")
    public val isData: Boolean
    //10.判断类是否为成员类
    @SinceKotlin("1.1")
    public val isInner: Boolean
    //11.判断类是否为companion object
    @SinceKotlin("1.1")
    public val isCompanion: Boolean 
    //12.返回类中定义的其他类,包括内部类(inner class声明的)和嵌套类(class声明的)
    public val nestedClasses: Collection<KClass<*>>
     //13.判断一个对象是否为此类的实例
    @SinceKotlin("1.1")
    public fun isInstance(value: Any?): Boolean
    //14.返回这个类的泛型列表
    @SinceKotlin("1.1")
    public val typeParameters: List<KTypeParameter>
    //15.类其直接基类的列表
    @SinceKotlin("1.1")
    public val supertypes: List<KType>
    //16.返回类所有的基类
    val KClass<*>.allSuperclasses: Collection<KClass<*>>
    //17.返回类的伴生对象companionObject
    val KClass<*>.companionObject: KClass<*>?
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    2.3 使用demo

    package com.yvan.demo.reflect
    
    import kotlin.reflect.KMutableProperty1
    import kotlin.reflect.full.*
    import kotlin.reflect.jvm.isAccessible
    
    //定义注解
    annotation class Anno
    
    @Deprecated("该类已经不推荐使用")
    @Anno
    class ReflectA(val name: String) {
    
        companion object{
            const val TAG = "ReflectA"
            fun show(){
    
            }
        }
    
        var age: Int = 0
    
        constructor() : this("ReflectA_")
    
        constructor(name: String, age: Int) : this(name) {
            this.age = age
        }
    
        fun print(str: String) {
            println("ReflectA print str $str")
        }
    
        fun sayHi(): String {
            println("ReflectA sayHi")
            return "sayHi"
        }
    
        class InnerClass
    }
    
    // 拓展方法
    fun ReflectA.exfun() {
        println("exfun")
    }
    
    // 拓展属性
    val ReflectA.foo: Double
        get() = 3.14
    
    
    fun main() {
        println("Hello word")
    
        val clazz = ReflectA::class
        println(clazz)
    
        println("ReflectA 的全部构造器如下:")
        clazz.constructors.forEach {
            println(it)
        }
    
        println("ReflectA 的主构造器如下:")
        println(clazz.primaryConstructor)
    
        println(" ")
        //通过functions属性获取该KClass对象所对应类的全部方法
        val funs = clazz.functions
        println("ReflectA 的全部方法如下:")
        funs.forEach { println(it) }
    
        println(" ")
        //通过 declaredFunctions 属性获取该KClass对象声明的全部方法
        val funs2 = clazz.declaredFunctions
        println("ReflectA 本身声明的全部方法如下:")
        funs2.forEach { println(it) }
    
        println(" ")
        //通过 memberExtensionFunctions 属性获取全部扩展方法
        val exetensionFunctions = clazz.memberExtensionFunctions
        println("ReflectA 声明的扩展方法如下:")
        exetensionFunctions.forEach { println(it) }
    
        println(" ")
        //通过decaredMemberProperties获取全部成员属性
        var memberProperties = clazz.declaredMemberProperties
        println("ReflectA 本身声明的成员属性如下:")
        memberProperties.forEach { println(it) }
    
        println(" ")
        //通过memberExtensionProperties属性获取该KClass对象的全部扩展属性
        var exProperties = clazz.memberExtensionProperties
        println("ReflectA 本身声明的扩展属性如下:")
        exProperties.forEach { println(it) }
    
        println(" ")
        //通过annotations属性获取该KClass对象所对应类的全部注解
        val anns = clazz.annotations
        println("ReflectA 的全部注解如下:")
        anns.forEach { println(it) }
        println("该KClass元素上的@Annot注解为:${clazz.findAnnotation<Anno>()}")
    
        println(" ")
        //通过nestedClasses属性获取所对应的全部嵌套类
        val inners = clazz.nestedClasses
        println("ReflectA 的全部内部类如下:")
        inners.forEach { println(it) }
    
        println(" ")
        //通过supertypes属性获取该类的所有父类型
        println("KClassTest的父类型为:${clazz.supertypes}")
    
    
        println(" ")
        println("---------- companion 对象 ---------") //
        val companion = clazz.companionObject // 返回也是一个 KClass
        if (companion != null){
            println("companion $companion")
            companion.declaredMemberProperties.forEach {
                println("companion declaredMemberProperties:  $it")
            }
            companion.declaredFunctions.forEach {
                println("companion declaredFunctions:  $it")
            }
        }
    
    
        println(" ")
    
    
        println("---------- 创建对象 ---------")
        println(" ")
        println("createInstance 创建实例")
        // createInstance() 方法调用无参数的构造器创建实例
        val inst2 = clazz.createInstance()
        println(inst2.name)
        println(inst2.age)
    
        println(" ")
        // primaryConstructor 主构造函数
        val cons1 = clazz.primaryConstructor
        val inst1 = cons1?.call("hello reflect")  // 参入参数
        println(inst1)
        println("inst1 " + inst1?.name)
    
        println(" ")
        println("第一个构造函数")
        val cons2 = clazz.constructors.first()
        println(cons2)
    
        println(" ")
    
        println("-------调用方法------")
        val funs3 = clazz.declaredFunctions
        val inst3 = clazz.createInstance()
        println("ReflectA 本身声明的全部方法如下:")
        funs3.forEach { println(it) }
        for (f in funs3) {
            if (f.name == "sayHi") {
                f.call(inst3)
            }
            if (f.name == "print") {
                f.call(inst3, "反射打印")
            }
        }
    
        println("\n")
        println("-------访问属性------")
        //通过decaredMemberProperties获取全部成员属性
        val memberProperties2 = clazz.declaredMemberProperties
        val inst4 = clazz.createInstance()
        println("ReflectA 本身声明的成员属性如下:")
        memberProperties2.forEach { println(it) }
        println("inst4 name: ${inst4.name}")
        memberProperties2.forEach {
            if (it.name == "age") {
                it as KMutableProperty1<ReflectA, Int>
                it.isAccessible = true
                it.set(inst4, 20)
                println(it.get(inst4))
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183

    3 Kotlin反射总结

    反射是一种在运行时动态访问对象属性和方法的方式,而不需事先确定这些属性是什么。
    一般来说当你访问一个对象的方法或者属性时,程序的源代码会因用一个具体的声明,编译器将静态解析这个引用并确保这个声明是存在的。但有时候你要编写能够使用任意类型的对象的代码,或者只能在运行时才能确定要访问的方法和属性的名称。

  • 相关阅读:
    vue3 effectScope解析
    Less is more VS 精一 [生活感悟]
    探究WPF中文字模糊的问题:TextOptions的用法
    ArduPilot开源飞控之AP_Baro_ExternalAHRS
    anaconda虚拟环境安装tensorflow GPU 2.9.0 cuda11.6 cuDNN 8.5
    数据库语句
    YOLO对于检测目标不全也被检测到了,如何改进?
    阿里P8大牛整理总结,影响全球250W工程师,两大阿里java开发手册
    SpringBoot面试题5:SpringBoot Starter的工作原理是什么?
    费曼学习法(Redis总结)
  • 原文地址:https://blog.csdn.net/u010687761/article/details/133237529