-
反射是允许程序在运行时访问程序结构的一类特性
-
程序结构包括:类,接口,方法,属性等语法特性
Kotlin 字节做了一套反射API库,这个库需要进行依赖
implementation("org.jetbrains.kotlin:kotlin-reflect")
反射的常见用途
- 列出类型的所有方法,属性,内部类等等
- 调用给定名称及签名方法或指定名称的属性
- 通过签名信息获取泛型实参的具体类型
- 访问运行时注解及其信息完成注入或者配置操作
反射常用的数据结构
数据结构 | 概念及说明使用 |
---|---|
KType | 描述未擦除的类型或泛型参数等,例如Map<String,Int>;可以通过typeOf或者一些类型获取对应父类,属性,函数参数等 |
KClass | 描述对象的实际类型,不包含泛型参数,例如 Map;可通过对象,类型名直接获得 |
KProperty | 描述属性,可通过属性引用,属性所在类的 KClass 获取 |
KFunction | 描述函数,可通过函数引用,函数所在类的 KClass 获取 |
获取泛型实参
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 进而读取泛型实参的方法
- 为数据类添加深拷贝
- 反射调用构造器构造数据类实例
- 实例之间的转换
- 可释放引用的不可空类型
参考自慕课网视频