【Kotlin精简】第6章 反射

news2024/11/18 3:32:10

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 反射优缺点

  1. Java 反射
    优点:无需引入额外依赖,首次使用速度相对较快
    缺点: 无法访问 Kotlin 语法特性,需对 Kotlin 生成的字节码足够了解

  2. Kotlin 反射
    优点: 支持访问 Kotlin 几乎所有特性,API 设计更友好
    缺点:引入 Kotin 反射库(2.5MB,编译后 400KB),首次调用慢

1.3 反射用途

  1. 在运行时判断任意一个**对象所属的类**
  2. 在运行时构造任意一个**类的对象**
  3. 在运行时判断任意一个**类所具有的成员变量和方法**
  4. 在运行时调用任意一个**对象的方法**

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反射总结

反射是一种在运行时动态访问对象属性和方法的方式,而不需事先确定这些属性是什么。
一般来说当你访问一个对象的方法或者属性时,程序的源代码会因用一个具体的声明,编译器将静态解析这个引用并确保这个声明是存在的。但有时候你要编写能够使用任意类型的对象的代码,或者只能在运行时才能确定要访问的方法和属性的名称。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1129583.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【反悔贪心】2022ICPC南京 G

Problem - G - Codeforces 题意 思路 首先容易发现&#xff0c;合并操作对平均攻击力有贡献&#xff0c;但是加一个1就没有贡献&#xff0c;因此首先考虑每次遇到0的时候都合并 但是很快发现如果这样的话&#xff0c;遇到-1就不一定有足够的1给你合并&#xff0c;因此在遇到…

Vite创建vue3+ts+pinia+vant项目起步流程

pnpm介绍&安装 本质上他是一个包管理工具&#xff0c;和npm/yarn没有区别&#xff0c;主要优势在于 包安装速度极快磁盘空间利用效率高 安装&#xff1a; npm i pnpm -g使用&#xff1a; npm命令pnpm等效npm installpnpm installnpm i axiospnpm add axiosnpm i webpa…

springboo单机多线程高并发防止重复消费的redis方案

springboo单机多线程高并发防止重复消费的redis方案 仅提供方案与测试。 想法&#xff1a;第一次收到userCode时&#xff0c;检查是否在redis中有&#xff0c;如果有&#xff0c;就表明已经消费了&#xff0c;返回抢单失败&#xff1b;否则&#xff0c;就去消费&#xff0c;顺…

EfficientFormerV2:全新的轻量级视觉Transformer

期刊&#xff1a;2023 IEEE/CVF International Conference on Computer Vision (ICCV) 标题&#xff1a;Rethinking&#xff08;重新审视&#xff09; Vision Transformers&#xff08;ViT&#xff09; for MobileNet Size and Speed&#xff08;MobileNet的规模和速度&#xf…

计算机组成原理-存储器概念

计算机组成原理-存储器 存储系统的基本概念 1.层次结构 可以直接被CPU读取: 高速缓存:cache主存储器: 主存和内存 辅助存储器: 辅存和外存 2.分类 1.按层次结构划分 如上面所示 2.按存储介质 半导体存储器磁表面存储器光存储器 3.按信息可更改性 r/w存储器ROM(只读存储器) 4…

Vue2 + Echarts实现3D地图下钻

一、npm安装组件&#xff1a; "echarts": "5.4.0","echarts-gl": "^2.0.9","element-china-area-data": "^5.0.2", 二、Vue页面 <template><div class"Map3D" id"Map3D" ref"…

Python基础入门例程9-NP9 十六进制数字的大小

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 示例1 解答&#xff1a; 说明&#xff1a; 描述 计算的世界&#xff0c;除了二进制与十进制&#xff0c;使用最多的就是十六进制了&#xff0c;现在使用input读入一个十六进制的数字&#xff0c;输出它的十进制数字…

30 个常用的 Linux 命令!

作者&#xff1a;JackTian 来源&#xff1a;公众号「杰哥的IT之旅」 ID&#xff1a;Jake_Internet 链接&#xff1a;30 个常用的 Linux 命令&#xff01; 命令 1&#xff1a;last用于显示用户最近登录信息&#xff0c;包括用户名、登录时间、登录来源等信息 单独执行last命令&…

开发直播带货APP:用户体验设计策略

在当今数字化时代&#xff0c;直播带货APP已经成为了电子商务领域的一股重要力量。这种形式的电子商务结合了实时直播和购物&#xff0c;吸引了数百万用户。然而&#xff0c;为了确保直播带货APP的成功&#xff0c;关键在于提供出色的用户体验。本文将探讨开发直播带货APP的用户…

iframe嵌入报表滚动条问题

当在iframe中嵌入报表时&#xff0c;可能会遇到滚动条的问题。下面是一个详细的介绍 1. 了解iframe&#xff1a; - iframe是HTML中的元素&#xff0c;用于在当前页面中嵌入另一个页面。 - 嵌入报表时常使用iframe&#xff0c;以便将报表以独立的方式展示&#xff0c;并与其他页…

MT4教程新手指南:一步步开启你的金融交易之旅!

本文将为您详细介绍如何使用MT4(MetaTrader 4)平台进行金融交易。MT4是全球最受欢迎的在线交易平台之一&#xff0c;它拥有强大的功能&#xff0c;包括图表分析工具、交易执行、订单管理等&#xff0c;可以帮助你更好地理解和参与金融市场。那么&#xff0c;让我们开始吧! **步…

基于正余弦算法的无人机航迹规划-附代码

基于正余弦算法的无人机航迹规划 文章目录 基于正余弦算法的无人机航迹规划1.正余弦搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用正余弦算法来优化无人机航迹规划。 1.正余弦…

31一维信号滤波(限幅滤波、中值滤波、均值滤波、递推平均滤波),MATLAB程序已调通,可直接运行。

一维信号滤波&#xff08;限幅滤波、中值滤波、均值滤波、递推平均滤波&#xff09;&#xff0c;MATLAB程序已调通&#xff0c;可直接运行。 31matlab、中值滤波、信号处理 (xiaohongshu.com)

structs2 重构成SpringBoot架构

# 目录 structs2 重构成SpringBoot架构 1.1 structs2架构&#xff1a; 1.2 springboot 架构 1.3 演化要点&#xff1a; 1.基于前端的展示层不需要修改 2.HttpServlet 将会有SpringBoot annotation 来处理 3.构建前置的Structs url 转发器&#xff0c;适配 4.ActionSupport将由…

9篇论文速览股票预测高分经典方案

作为一直以来的烫门&#xff0c;股票预测因其非线性、高度波动性和复杂性等原因&#xff0c;成为了金融量化领域的一大难题。以往的解决方案主要围绕机器学习展开&#xff0c;如今&#xff0c;基于深度学习的股票预测方法有了许多新的突破。 为了帮助大家更深入地了解股票预测…

防止消息丢失与消息重复——Kafka可靠性分析及优化实践

系列文章目录 上手第一关&#xff0c;手把手教你安装kafka与可视化工具kafka-eagle Kafka是什么&#xff0c;以及如何使用SpringBoot对接Kafka 架构必备能力——kafka的选型对比及应用场景 Kafka存取原理与实现分析&#xff0c;打破面试难关 防止消息丢失与消息重复——Kafka可…

ToDesk等远程软件连接主机无法更改分辨率 - 解决方案

问题 使用ToDesk等远程软件连接自己的Linux或Windows主机时&#xff0c;若主机已连接显示器&#xff0c;则可通过系统设置更改显示分辨率。但如果主机没有连接显示器或显示器的电源关闭&#xff0c;则无法正常调整分辨率。下文介绍解决方案。 解决方案 方案1&#xff1a;连接…

多跳推理真的可解释吗?10.24

多跳推理真的可解释吗 摘要1 引言2 相关工作2.1 多跳推理2.2 基于规则的推理2.3 可解释性评估 3 基础知识4 基准测试4.1 数据集构建4.2 评估框架4.3 近似可解释性评分4.4 Benchmark with Manual Annotation4.5 使用挖掘规则的基准 实验 摘要 近年来&#xff0c;多跳推理在获取…

BUUCTF wireshark 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 黑客通过wireshark抓到管理员登陆网站的一段流量包&#xff08;管理员的密码即是答案) 密文&#xff1a; 下载附件&#xff0c;解压后得到一个.pcap文件。 解题思路&#xff1a; 1、双击文件&#xff0c;在wires…

测试用例的设计方法(全):边界值分析方法

一.方法简介 1.定义&#xff1a;边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充&#xff0c;这种情况下&#xff0c;其测试用例来自等价类的边界。 2.与等价划分的区别 1)边界值分析不是从某等价类中随便挑…