[toc]
1. Kotlin 反射
Kotlin 的反射需要集成 org.jetbrains.kotlin:kotlin-reflect
仓库,版本保持与 kotlin 一致。
1 | implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" |
1.1 Kotlin 反射类图
图片引用《Kotlin 核心编程》
Java 的反射类图
通过 kotlin 和 java 的对比,更容易理解 kotlin 的反射
- Kotlin 的反射类都是基于
KAnnotatedElement
, 而 Java 的反射类都是基于AnnotateElement
; - Kotlin 的 KCallable 和 Java 的 AccessiableObject 都是可用元素;
- Kotlin 的 KProperty 和 Java 的 Field 不太相同。 Kotlin 的 KProperty 通常指相应的 Getter 和 Setter 整体作为一个 KProperty(不存在字段的概念),而 Java 的 Field 通常仅仅指字段本身。
日常使用的 Kotlin 反射
创建实例
- ReflectA::class
- KClass.createInstance
- KClass.primaryConstructor 主构造函数
获取实例的函数
- 本身及父类的函数 KClass.functions
- 本身声明的函数 KClass.declaredFunctions
- 拓展的函数 KClass.memberExtensionFunctions
获取实例的成员变量
- 本身的成员属性 KClass.declaredMemberProperties
- 拓展属性 KClass.memberExtensionProperties
获取实例的 companion
KClass.companionObject获取注解
KClass.annotations获取内部类
KClass.nestedClasses
2.创建实例
无参构造
1 | val clazz = ReflectA::class |
有参构造
1 | val cons1 = clazz.primaryConstructor |
说明
- KClass.createInstance 是调用无参数的构造函数
- KClass.primaryConstructor 是主构造函数,如果有参数,可以调用它的 call 方法传入参数
例子
后面的例子都是以 ReflectA
类为例
1 | //定义注解 |
调用的例子:
1 | println("---------- 创建对象 ---------") |
输出
———- 创建对象 ———
createInstance 创建实例
ReflectA_
0
com.yxhuang.androiddailydemo.reflect.ReflectA@7b9a4292
inst1 hello reflect
第一个构造函数
fun(): com.yxhuang.androiddailydemo.reflect.ReflectA
3.通过反射调用方法 KFunction
通过 KClass.declaredFunctions 获取,返回是一个 KFunction 列表
1 | println("-------调用方法------") |
输出
——-调用方法——
ReflectA 本身声明的全部方法如下:
fun com.yxhuang.androiddailydemo.reflect.ReflectA.print(kotlin.String): kotlin.Unit
fun com.yxhuang.androiddailydemo.reflect.ReflectA.sayHi(): kotlin.String
ReflectA print str 反射打印
ReflectA sayHi
4. 通过反射获取属性
通过 KClass.declaredMemberProperties 获取,返回是 KProperty1 列表。
KProperty 代码属性,它是 KCallable 的子类,
主要接口有
1 | public actual interface KProperty<out V> : KCallable<V> { |
获取例子
1 | println("-------访问属性------") |
输出
——-访问属性——
ReflectA 本身声明的成员属性如下:
var com.yxhuang.androiddailydemo.reflect.ReflectA.age: kotlin.Int
val com.yxhuang.androiddailydemo.reflect.ReflectA.name: kotlin.String
inst4 name: ReflectA_
20
5.获取实例的 companion
通过 KClass.companionObject 获取,返回也是一个 KClass 对象
1 | println("---------- companion 对象 ---------") // |
输出
———- companion 对象 ———
companion class com.yxhuang.androiddailydemo.reflect.ReflectA$Companion
companion declaredMembers: val com.yxhuang.androiddailydemo.reflect.ReflectA.Companion.TAG: kotlin.String
companion declaredFunctions: fun com.yxhuang.androiddailydemo.reflect.ReflectA.Companion.show(): kotlin.Unit
6. 获取注解
通过 KClass.annotations 获取注解,返回是一个Annotation列表
1 | //通过annotations属性获取该KClass对象所对应类的全部注解 |
输出
ReflectA 的全部注解如下:
@kotlin.Deprecated(level=WARNING, replaceWith=@kotlin.ReplaceWith(imports=[], expression=), message=该类已经不推荐使用)
@com.yxhuang.androiddailydemo.reflect.Anno()
该KClass元素上的@Annot注解为:@com.yxhuang.androiddailydemo.reflect.Anno()
7.获取内部类
通过 KClass.nestedClasses 获取,返回是一个内部类的 KClass 列表
1 | //通过nestedClasses属性获取所对应的全部嵌套类 |
输出
ReflectA 的全部内部类如下:
class com.yxhuang.androiddailydemo.reflect.ReflectA\$Companion
class com.yxhuang.androiddailydemo.reflect.ReflectA$InnerClass
8.完整的代码
1 | package com.yxhuang.androiddailydemo.reflect |
9. 问题
9.1 打包混淆问题
在打包混淆之后,如果出现问题
1 | java.lang.IllegalStateException: No BuiltInsLoader implementation was found. Please ensure that the META-INF/services/ is not stripped from your application and that the Java virtual machine is not running under a security manager |
这是由于混淆导致的,解决办法是在 proguard-rules.pro 中添加下面的规矩即可
1 | -keep class kotlin.reflect.jvm.internal.impl.** |