1 反射简介
反射机制
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性。
1.1 Kotlin反射
我们对比Kotlin和Java的反射类图。
1.1.1 Kotlin反射常用的数据结构
数据结构 | 概念及使用说明 |
---|---|
KType | 描述未擦除的类型或泛型参数等,例如 Map<String,Int>;可通过 typeof 或者以下类型获取对应的父类、属性、函数参数等 |
KClass | 描述对象的实际类型,不包含泛型参数,例如Map可通过对象、类型名直接获得 |
KProperty | 描述属性,可通过属性引用、属性所在类的 KClass 获取 |
KFunction | 描述函数,可通过函数引用、函数所在类的 KClass 获取 |
1.2 对比Java反射
1.2.1 Kotlin与Java 反射优缺点
-
Java 反射
优点:无需引入额外依赖,首次使用速度相对较快
缺点: 无法访问 Kotlin 语法特性,需对 Kotlin 生成的字节码足够了解 -
Kotlin 反射
优点: 支持访问 Kotlin 几乎所有特性,API 设计更友好
缺点:引入 Kotin 反射库(2.5MB,编译后 400KB),首次调用慢
1.3 反射用途
- 在运行时判断任意一个**
对象所属的类
** - 在运行时构造任意一个**
类的对象
** - 在运行时判断任意一个**
类所具有的成员变量和方法
** - 在运行时调用任意一个**
对象的方法
**
2 Kotlin反射
2.1 反射使用
Kotlin
的反射需要集成 org.jetbrains.kotlin:kotlin-reflect
仓库,版本保持与 Kotlin
一致。
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
在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
获取了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
2.2 常用API
2.2.1 构造函数Constructor
//返回这个类的所有构造器
public val constructors: Collection<KFunction<T>>
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, *>>
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<*>?
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))
}
}
}
3 Kotlin反射总结
反射
是一种在运行时
动态访问对象属性和方法
的方式,而不需事先确定这些属性是什么。
一般来说当你访问一个对象的方法或者属性时,程序的源代码会因用一个具体的声明,编译器将静态解析这个引用并确保这个声明是存在的。但有时候你要编写能够使用任意类型的对象的代码,或者只能在运行时才能确定要访问的方法和属性的名称。