反射是允许程序在运行时访问程序结构的一类特性
程序结构包括:类,接口,方法,属性等语法特性
Kotlin 字节做了一套反射API库,这个库需要进行依赖
implementation("org.jetbrains.kotlin:kotlin-reflect")
反射的常见用途
列出类型的所有方法,属性,内部类等等
调用给定名称及签名方法或指定名称的属性
通过签名信息获取泛型实参的具体类型
访问运行时注解及其信息完成注入或者配置操作
反射常用的数据结构
获取泛型实参
fun main() { /** * declaredFunctions:获取该类中所有的函数 * first:判断是否为指定的函数名,如果相等则返回出去 * returnType:获取返回值 * arguments:返回值的泛型 */ Api::class.declaredFunctions.first { it.name == "getUser" } .returnType.arguments.forEach { println(it.type) } //直接拿到函数引用,其他的和上面一样 Api::getUser.returnType.arguments.forEach { println(it) } val subType = SubType() subType.typeParameter.let { println(it) } } class UserDTO interface Api { fun getUser(): List<UserDTO> } abstract class SuperType<t> { val typeParameter by lazy { /** * 抽象类不能有实例,所以这里的 this 是子类的 * supertypes:获取父类类型列表 * first:获取第一个 * arguments:拿到泛型 * type:类型 */ this::class.supertypes.first().arguments.first().type!! } val typeParameterJava by lazy { } } class SubType : SuperType<String>()
案例:深拷贝
data class Person(val id: Int, val name: String, val group: Group) data class Group(val id: Int, val name: String, val location: String) fun main() { val person = Person( 0, "345", Group(0, "Kotlin.cn", "China") ) val deep = person.deepCopy() val copied = person.copy() println(person.group === copied.group) println(person.group === deep.group) println(deep) } fun <T : Any> T.deepCopy(): T { //如果不是数据类就直接返回 if (!this::class.isData) { return this } /** * primaryConstructor:获取该类的主构造函数,如果没有返回 null */ return this::class.primaryConstructor!!.let { primaryConstuctor -> /** * parameters:构造方法中的参数 */ primaryConstuctor.parameters.map { parameter -> /** * memberProperties:,类中所有非扩展属性 */ val value = (this::class as KClass<T>).memberProperties.first { it.name == parameter.name }.get(this) //属性是否为数据类 if ((parameter.type.classifier as? KClass<*>)?.isData == true) { //如果是则进行深度拷贝 parameter to value?.deepCopy() } else { parameter to value } //call/callBy 创建对象 }.toMap().let(primaryConstuctor::callBy) } }
案例:映射
data class UserVO(val login: String, val avatarUrl: String) data class UserDTO( var id: Int, var login: String, var avatarUrl: String, var url: String, var htmlUrl: String ) fun main() { val userDTO = UserDTO( 0, "345", "https://www.baidu.com", "https://github", "https://httpurl" ) val userVo: UserVO = userDTO.mapAs() println(userVo) val userMap = mapOf( "id" to 0, "login" to "1", "avatarUrl" to "2", "url" to "3" ) val userVOFromMap: UserVO = userMap.mapAs() println(userVOFromMap) } inline fun <reified From : Any, reified TO : Any> From.mapAs(): TO { return From::class.memberProperties.map { it.name to it.get(this) }.toMap().mapAs() } inline fun <reified TO : Any> Map<String, Any?>.mapAs(): TO { return TO::class.primaryConstructor!!.let { it.parameters.map { kParameter -> //如果接受null,则返回,否则抛出异常 //this[kParameter.name] :从当前的 map 中寻找。如果找到了则就是拿到了 value,否则异常 kParameter to (this[kParameter.name] ?: if (kParameter.type.isMarkedNullable) null else throw IllegalArgumentException("失败")) }.toMap().let(it::callBy)//构建对象 } }
案例:释放对象引用不可空类型
class ReleasableNotNull<T : Any> { private var value: T? = null operator fun getValue(thisRef: Any, kProperty: KProperty<*>): T { return value ?: throw IllegalArgumentException("使用错误") } operator fun setValue(thisRef: Any, kProperty: KProperty<*>, value: T) { this.value = value } fun isInitialized() = value != null fun release() { value = null } } //扩展属性 inline val KProperty0<*>.isInitialized: Boolean get() { isAccessible = true return (this.getDelegate() as ReleasableNotNull<*>).isInitialized() } //扩展方法 fun KProperty0<*>.release() { isAccessible = true (this.getDelegate() as ReleasableNotNull<*>).release() } class Bitmap(val with: Int, val height: Int) class Activity { private var bitmap by ReleasableNotNull<Bitmap>() fun onCreate() { println(::bitmap.isInitialized) bitmap = Bitmap(234, 353) println(::bitmap.isInitialized) } fun onDestroy() { println(::bitmap.isInitialized) ::bitmap.release() println(::bitmap.isInitialized) } } fun main() { val activity = Activity() activity.onCreate() activity.onDestroy() }
false
true
true
false
通过反射调用构造函数、
fun main() { //获取对象的class val cls = Person(23, "张三").javaClass.kotlin //调用构造器 2 val cons = cls.primaryConstructor val per1 = cons?.call(100, "李四") println(per1) //2 val per2 = cls.primaryConstructor.let { var i = 0 val s = it!!.parameters.map { i++ when (i) { 1 -> it to 2 2 -> it to "哈哈" else -> it to "" } }.toMap() it.callBy(s) } println(per2) } class Person(val age: Int, val name: String) { val p = 1 fun a() {} private fun b() {} override fun toString(): String { return "姓名:$name 年龄:$age" } }
反射
反射是啥
数据结构:KType,KClass,KProperty,KFunction
获取泛型实参
了解泛型的实现机制
料及实参在字节码中的存储机制
掌握反射获取对应类型的 KType 进而读取泛型实参的方法
为数据类添加深拷贝
反射调用构造器构造数据类实例
实例之间的转换
可释放引用的不可空类型