【Kotlin精简】第6章 反射

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.reflectimport 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 = 0constructor() : 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: Doubleget() = 3.14fun main() {println("Hello word")val clazz = ReflectA::classprintln(clazz)println("ReflectA 的全部构造器如下:")clazz.constructors.forEach {println(it)}println("ReflectA 的主构造器如下:")println(clazz.primaryConstructor)println(" ")//通过functions属性获取该KClass对象所对应类的全部方法val funs = clazz.functionsprintln("ReflectA 的全部方法如下:")funs.forEach { println(it) }println(" ")//通过 declaredFunctions 属性获取该KClass对象声明的全部方法val funs2 = clazz.declaredFunctionsprintln("ReflectA 本身声明的全部方法如下:")funs2.forEach { println(it) }println(" ")//通过 memberExtensionFunctions 属性获取全部扩展方法val exetensionFunctions = clazz.memberExtensionFunctionsprintln("ReflectA 声明的扩展方法如下:")exetensionFunctions.forEach { println(it) }println(" ")//通过decaredMemberProperties获取全部成员属性var memberProperties = clazz.declaredMemberPropertiesprintln("ReflectA 本身声明的成员属性如下:")memberProperties.forEach { println(it) }println(" ")//通过memberExtensionProperties属性获取该KClass对象的全部扩展属性var exProperties = clazz.memberExtensionPropertiesprintln("ReflectA 本身声明的扩展属性如下:")exProperties.forEach { println(it) }println(" ")//通过annotations属性获取该KClass对象所对应类的全部注解val anns = clazz.annotationsprintln("ReflectA 的全部注解如下:")anns.forEach { println(it) }println("该KClass元素上的@Annot注解为:${clazz.findAnnotation<Anno>()}")println(" ")//通过nestedClasses属性获取所对应的全部嵌套类val inners = clazz.nestedClassesprintln("ReflectA 的全部内部类如下:")inners.forEach { println(it) }println(" ")//通过supertypes属性获取该类的所有父类型println("KClassTest的父类型为:${clazz.supertypes}")println(" ")println("---------- companion 对象 ---------") //val companion = clazz.companionObject // 返回也是一个 KClassif (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.primaryConstructorval 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.declaredFunctionsval 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.declaredMemberPropertiesval 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 = trueit.set(inst4, 20)println(it.get(inst4))}}
}

3 Kotlin反射总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Egg.js使用MySql数据库

最近在接手一个项目&#xff0c;vuenuxtegg&#xff0c;我也是刚开始学习egg.js&#xff0c;所以会将自己踩的坑都记录下来。 安装mysql 使用sequelize连接数据库&#xff0c;首先安装egg-sequelize和mysql2。 npm install --save egg-sequelize mysql2打开package.json文件…

(a /b)*c的值

系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…

JavaWeb——关于servlet种mapping地址映射的一些问题

6、Servlet 6.4、Mapping问题 一个Servlet可以指定一个映射路径 <servlet-mapping><servlet-name>hello</servlet-name><url-pattern>/hello</url-pattern> </servlet-mapping>一个Servlet可以指定多个映射路径 <servlet-mapping>&…

DevOps持续集成-Jenkins(2)

文章目录 DevOpsDevOps概述Integrate工具&#xff08;centos7-jenkins主机&#xff09;Integrate概述Jenkins介绍CI/CD介绍Linux下安装最新版本的Jenkins⭐Jenkins入门配置安装必备插件⭐安装插件&#xff08;方式一&#xff1a;可能有时会下载失败&#xff09;安装插件&#x…

SpringCloudGateway 入门

目录 POM 依赖一、内容网关的作用Spring-Cloud-Gateway的核心概念 二、基于Ribbon的负载均衡三、核心概念详细3.1 断言 Predicate3.2 过滤器3.2.1 内置过滤器3.2.2 自定义过滤器构造器&#xff08;原理&#xff09;资源结构Route / Predicate 的构造器构造器的增强器整体协同关…

软考系列(系统架构师)- 2009年系统架构师软考案例分析考点

试题一 软件架构设计 【问题1】&#xff08;9分&#xff09; 软件质量属性是影响软件架构设计的重要因素。请用200字以内的文字列举六种不同的软件质量属性名称并解释其含义。 常见的软件质量属性有多种&#xff0c;例如性能&#xff08;Performance)、可用性&#xff08;Ava…

VirtualBox 安装 麒麟Linux

为了验证Oracle EM是否可以管理麒麟OS和其上的Oracle数据库&#xff0c;今天试着在VirtualBox上装了麒麟Linux&#xff0c;也就是银河麒麟。整个过程比较顺畅。 选定ISO文件后&#xff0c;操作系统自动识别为Red Hat。勾选“跳过自动安装”&#xff1a; 内存和CPU选的默认值&…

蓝桥杯 Java 括号序列

本算法需要把问题分解成三步&#xff1a; 第一步&#xff1a;算出 ((() 填充 ( 的方案 第二步&#xff1a;算出 ((() 填充 ) 的方案 第三步&#xff1a;把两个方案相乘 第二步可以把原方案当成将 ((() 逆转成 ())) 再填充 ( &#xff0c;这样就可以重复第一步用的算法 第一步…

笔记:电子设备接地,接的到底是什么地?

电路中有“地”&#xff0c;设备中有“地”&#xff1b;都是“地”&#xff0c;此地非彼地。 混淆的原因 有些混淆&#xff0c;是以为中文翻译造成的&#xff0c;英文所有Ground都统一翻译为“地”&#xff1b; 例1&#xff1a;英文Circuit Ground&#xff0c;应该翻译为电路…

深入理解Java IO流: 包括字节流和字符流的用法、文件读写实践

文章目录 &#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出版社签约作者、产品软文创造者、技术文章评审老师、问卷调查设计师、个人社区创始人、开源项目贡献者。&#x1f30e;跑过十五…

ruoyi-nbcio版本从RuoYi-Flowable-Plus迁移过程记录

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 从KonBAI / RuoYi-Flowable-Plus 项目移植过来&#xff0c;开始用yarn install之后yarn run dev 还是有问…

Redis 持久化配置,RDB和AOF方式配置说明

文章目录 一、概述二、RDB 持久化方式配置三、AOF 持久化方式配置 如果您对Redis的了解不够深入请关注本栏目&#xff0c;本栏目包括Redis安装&#xff0c;Redis配置文件说明&#xff0c;Redis命令和数据类型说明。 一、概述 Redis 持久化是指将 Redis 数据存储到磁盘上&#x…