这一节为Kotlin反射,主要是在Kotlin中时用Java-Api来实现反射,使用Kotlin本身支持的反射API进行反射。还有2者的对比。要是对Java的反射不是很熟悉,可以花几分钟的时间先去网上找些Java反射的文章。关于Java的反射并不是这节的主要内,同时反射中也涉及到泛型的知识。其实有很多反射的地方关于泛型我也不敢说完全明白,也在代码中加了很多TODO,希望以后慢慢能熟能生巧,慢慢理解。
val clazz1: KProperty0> = person::javaClass
val clazz3: Class = clazz1.get()
val clazz2: Class = person::class.java
因为是调用Java的API,那么这里只写一些简单的调用,具体Java反射原理和常用API可以找些文章,网上很多
@Poko
data class Person(val name: String, val age: Int)
//这里使用的无参数构造方法,之前说过data class是没有无参数的构造方法的
//需要用noArg库
val person2 = clazz1.get().newInstance()
val person3 = clazz2.getConstructor(String::class.java, Int::class.java).newInstance("pack", 15)
// val name1=clazz2.getDeclaredField("name").get(person3)//直接调用会报错 因为name是private的 无法访问 需要加上isAccessible=true
val name2 = clazz2.getDeclaredField("name").apply { isAccessible = true }.get(person3)
val person4 = clazz2.getDeclaredMethod("copy", String::class.java, Int::class.java).invoke(person3, "pack_copy", 18)
clazz2.getDeclaredField("name").apply { isAccessible = true }.set(person3, "rose")//修改参数
在Java和Kotlin中,final的属性也是可以被修改的
被反射的Kotlin类
@Poko
class AnnotationTest1(val name: String = "name1")
@Poko
@Poko2
class AnnotationTest2(val name: String = "name2")
class AnnotationTest3(@Poko val name: String = "name3")
class AnnotationTest4(@Poko3 @Poko4 val name: String = "name4")
fun Person.sayHello() {
println(this.name)
}
fun sayHello() {
println("say Hello World !!!")
}
首先要明白一点Kotlin(如Main.kt)类,在编译后会生成MainKt类,但是这个类在Kotlin中时找不到的(在Java中可以找到),所以我们想在Kotlin中获取Kt类,可以使用方法Class.forName("")。
//扩展方法
Class.forName("com.qinglianyun.kotlin.class8.Main8_2Kt")
.getDeclaredMethod("sayHello", Person::class.java)
.invoke(null, Person("kotlin hello", 3))
//包级方法
Class.forName("com.qinglianyun.kotlin.class8.Main8_2Kt")
.getDeclaredMethod("sayHello")
.invoke(null)
val poko = Class.forName("com.qinglianyun.kotlin.class8.AnnotationTest1")
.getAnnotation(Poko::class.java)
Class.forName("com.qinglianyun.kotlin.class8.AnnotationTest3")
.getDeclaredField("name").annotations.forEach {
println("AnnotationTest3: $it")//什么都打印不出来 因为注解分注解类型 AnnotationTarget
}
//获取属性注解
Class.forName("com.qinglianyun.kotlin.class8.AnnotationTest4")
.getDeclaredField("name").annotations.forEach {
println("AnnotationTest4: $it")
关于注解这里需要说下:
1-6是注解相关知识,这部分参考Java注解,Java 注解(Annotation)
首先Kotlin的反射API是需要引入库的
//Kotlin 反射工具包
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
被访问的数据类:
@Poko //生成无参数构造器
data class People(val name: String, @Poko5 var age: Int)//primaryConstructor
{
fun hello1() {
println("hello1")
}
fun hello2(method: String) {
println("hello2: $method")
}
fun String.times(other: Int) {
println("类对象中的扩展方法sayHello2")
}
}
fun People.sayHello1() {
println("类文件的扩展方法sayHello1")
}
class NoPrimaryConstructor {
constructor() {
println("not primaryConstructor, no args")
}
constructor(num: Int) {
println("not primaryConstructor, have args:$num")
}
}
val Kclazz1 = People::class//类获取
val Kclazz2 = people::class//对象获取
val Kclazz3 = people.javaClass.kotlin//对象获取
val primaryConstructor = Kclazz2.primaryConstructor!!
val Kpeople1 = primaryConstructor.call("k-mark-1", 18)
println("Kpeople1: $Kpeople1")
/**
* 无(主构造器)
*/
val Kpeople2 = NoPrimaryConstructor::class.primaryConstructor?.call()//无住构造器
println("Kpeople2: $Kpeople2")//输出 null
//正确访问
val call1 = NoPrimaryConstructor::class.constructors.first().call()
val call = NoPrimaryConstructor::class.constructors.last().call(2)
Kclazz2.memberProperties.forEach(::println)
Kclazz3.memberProperties.forEach(::println)
(Kclazz3.memberProperties.first {
it.name == "age"
} as? KMutableProperty1)?.set(Kpeople1, 11)
println("KMutableProperty1 Kclazz3: $Kpeople1")
(Kclazz2.memberProperties.first {
it.name == "age"
}as? KMutableProperty1)?.set(Kpeople1, 13)
println("KMutableProperty1 Kclazz2: $Kpeople1")
Kclazz3.memberFunctions.forEach {
println("function: $it")
}
Kclazz3.memberFunctions.forEach {
println("name: ${it.name}")
if (it.name == "hello2") {
it.call(people, "你好!!!")
}
}
Kclazz3.memberExtensionFunctions.forEach(::println)
Kclazz3.memberExtensionFunctions.forEach {
println(it.name)
}
Kclazz3.annotations.forEach(::println)//访问类的注解
Kclazz3.memberProperties.first {
it.name == "age"
}.annotations.forEach {
println("annotations: $it")
}
Kclazz3.members.forEach(::println)
关于Kotlin反射有些地方比较难理解。因为是笔记很多我也是不是很清晰,反射就算是放在Java也属于高级语法了。慢慢磨练熟悉,多用多看,相信自己。鼓励自己。加油
Github源码直接运行,包含全部详细笔记