Kotlin 之反射详解

简介: Kotlin 之反射详解

反射是允许程序在运行时访问程序结构的一类特性


程序结构包括:类,接口,方法,属性等语法特性


Kotlin 字节做了一套反射API库,这个库需要进行依赖


implementation("org.jetbrains.kotlin:kotlin-reflect")


反射的常见用途


列出类型的所有方法,属性,内部类等等

调用给定名称及签名方法或指定名称的属性

通过签名信息获取泛型实参的具体类型

访问运行时注解及其信息完成注入或者配置操作


反射常用的数据结构


image.png


获取泛型实参


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 进而读取泛型实参的方法

为数据类添加深拷贝

反射调用构造器构造数据类实例

实例之间的转换

可释放引用的不可空类型


相关文章
|
Java 编译器 API
Java 反射 VS Kotlin 反射
Java 反射 VS Kotlin 反射
458 0
|
4天前
|
Java 数据库 Android开发
【专栏】构建高效 Android 应用:探究 Kotlin 多线程优化策略
【4月更文挑战第27天】本文探讨了Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理。通过案例分析展示了网络请求、图像处理和数据库操作的优化实践。同时,文章指出并发编程的挑战,如性能评估、调试及兼容性问题,并强调了多线程优化对提升应用性能的重要性。开发者应持续学习和探索新的优化策略,以适应移动应用市场的竞争需求。
|
5天前
|
传感器 Android开发 开发者
构建高效Android应用:Kotlin的协程与Flow
【4月更文挑战第26天】随着移动应用开发的不断进步,开发者寻求更简洁高效的编码方式以应对复杂多变的业务需求。在众多技术方案中,Kotlin语言凭借其简洁性和强大的功能库逐渐成为Android开发的主流选择。特别是Kotlin的协程和Flow这两个特性,它们为处理异步任务和数据流提供了强大而灵活的工具。本文将深入探讨如何通过Kotlin协程和Flow来优化Android应用性能,实现更加流畅的用户体验,并展示在实际开发中的应用实例。
|
5天前
|
安全 数据处理 Android开发
构建高效Android应用:Kotlin协程的实践之路
【4月更文挑战第26天】 在面对现代Android开发时,性能优化和流畅的用户体验成为了开发者们追求的目标。Kotlin作为一种现代化的编程语言,通过其协程特性为Android应用带来了前所未有的并发处理能力。本文将深入探讨如何利用Kotlin协程提升Android应用的响应性和效率,同时保持代码的简洁性。我们将从协程的基础概念出发,逐步揭示如何在实际应用中运用这些强大的工具,以及它们如何改善应用架构和用户交互体验。
|
23小时前
|
安全 Android开发 开发者
构建高效Android应用:采用Kotlin与Jetpack的实践指南
【4月更文挑战第30天】 在移动开发领域,随着技术的不断进步,为了提高应用的性能和用户体验,开发者们不断地探索新的工具和框架。对于Android平台而言,Kotlin语言以其简洁性和功能性成为了开发的首选。而Jetpack组件则提供了一套高质量的库、工具和指南,帮助开发者更轻松地构建高质量的应用程序。本文将探讨如何结合Kotlin语言和Jetpack组件来优化Android应用的开发流程,提升应用性能,并保证代码的可维护性和可扩展性。
|
1天前
|
算法 安全 Android开发
深入理解操作系统的内存管理机制构建高效Android应用:Kotlin的协程优势
【4月更文挑战第30天】 在现代计算机系统中,操作系统的内存管理是确保系统高效、稳定运行的关键。本文将探讨操作系统内存管理的核心技术,包括内存分配、虚拟内存、分页和分段等概念,以及它们是如何协同工作以提高内存利用率和系统性能的。通过对这些技术的详细分析,我们可以更好地理解操作系统背后的原理,并评估不同内存管理策略对系统行为的影响。 【4月更文挑战第30天】 在移动开发领域,尤其是针对Android平台,性能优化和流畅的用户体验始终是开发者追求的核心目标。随着Kotlin语言的普及,协程作为其在异步编程领域的杀手锏特性,已经逐渐成为提高应用性能和简化代码结构的重要工具。本文将深入探讨Kotli
|
1天前
|
数据库 Android开发 开发者
构建高效Android应用:采用Kotlin与Jetpack的实践指南
【4月更文挑战第30天】 随着移动开发技术的不断演进,Android平台提供了多种工具和框架以提升应用性能和开发效率。在本文中,我们将深入探讨如何结合Kotlin语言的简洁性和Android Jetpack组件的强大功能来构建一个既高效又可维护的Android应用。通过分析现代Android应用架构的关键要素,我们将展示如何利用Kotlin的特性以及如何整合Jetpack中的LiveData、ViewModel和Room等组件,以实现响应式编程、数据持久化和生命周期管理。
|
2天前
|
存储 数据库 Android开发
构建高效Android应用:采用Kotlin与Jetpack的实践指南
【4月更文挑战第29天】 在现代移动开发领域,构建一个既高效又稳定的Android应用对于开发者来说是一个持续的挑战。随着技术的不断进步和用户需求的日益增长,传统的开发方法已不足以满足市场的要求。本文将深入探讨如何结合Kotlin编程语言以及Android Jetpack组件,来提升Android应用的性能、稳定性及开发效率。通过分析Kotlin的优势、介绍Jetpack的核心组件,并结合实际案例,我们将展示如何在实际项目中应用这些技术,以期达到优化应用架构、提高代码质量和加快开发流程的目的。
10 1
|
3天前
|
数据处理 调度 Android开发
构建高效Android应用:探究Kotlin的协程优势
【4月更文挑战第28天】 随着移动应用开发日趋复杂,传统的线程和异步处理模型在处理并发任务时显得笨重且易出错。本文深入分析了Kotlin协程作为一种轻量级线程管理方案的优势,探讨了其在Android应用中实现流畅用户界面和提升性能的潜力。通过对协程原理的剖析以及与现有技术的比较,揭示了如何利用协程优化应用结构、简化代码逻辑,并提高应用的响应性和可维护性。
|
5天前
|
Java 测试技术 Android开发
构建高效Android应用:探究Kotlin与Java的性能对比
【4月更文挑战第26天】 在移动开发领域,性能优化一直是开发者追求的重要目标。随着Kotlin的兴起,其在Android平台上的应用逐渐增多,但关于Kotlin与Java在性能方面的对比,社区中仍存在诸多讨论。本文通过实际的性能测试,分析比较了使用Kotlin和Java编写的Android应用在多个维度上的运行效率,旨在为开发者提供一个明确的性能参考,帮助他们在选择编程语言时做出更加明智的决策。