前言
kotlin反射的应用一般用::操作符
获取类引用
val TAG = A::class.simpleName
反射是用来获取类运行信息,语法结构:
Classname:class
类名后加::class获取指定类的引用KClass类型的值。获取Java类的引用,在KClasss上加上.java属性。KClass是kotlin体哦那个获取运行时类信息的类,包含运行时所需要的各种属性
public actual interface KClass<T : Any> : KDeclarationContainer, KAnnotatedElement, KClassifier {
public actual val simpleName: String?
public actual val qualifiedName: String?
public val constructors: Collection<KFunction<T>>
public actual fun isInstance(value: Any?): Boolean
......
}
Kotlin最终要编译成Java字节码
val a = A::class
对应的反编译成Java的代码:
String a = Reflection.getOrCreateKotlinClass(A.class).getSimpleName();
看下getOrCreateKotlinClass调用链:
public static KClass getOrCreateKotlinClass(Class javaClass) {
return factory.getOrCreateKotlinClass(javaClass);
}
public KClass getOrCreateKotlinClass(Class javaClass) {
return new ClassReference(javaClass);
}
public class ClassReference(override val jClass: Class<*>) : KClass<Any>, ClassBasedDeclarationContainer {
override val simpleName: String?
get() = getClassSimpleName(jClass)
...
}
public fun getClassQualifiedName(jClass: Class<*>): String? = when {
...
else -> classFqNames[jClass.name] ?: jClass.canonicalName
}
canonicalName属性通过Java中Class对象getSimpleName方法获取的。KClass对象在编译期间通过Java中Class对象间接获取运行信息。
可调用的引用
所有可调用引用的公共超类型是KCallable<out R>,R是返回值类型。
属性引用
class Delegate{
operator fun getValue(thisRef:Any?,prop:KProperty<*>):String{
return "$thisRef name:${prop.name}"
}
}
KProperty是Kotlin封装的一个存储属性相关信息的接口,它继承自KCallable接口
val name:String get() = "name"
fun test() {
val pro = ::name
println(pro)
}
输出:
property name (Kotlin reflection is not available)
反编译后,PropertyReference0Impl这个类是实现了KProperty接口。test函数中创建了ReferenceClass对象,然后获取name属性的值。
函数引用
函数类型实例使用::运算符
val name:String get() = "name"
fun main() {
val refMethod = ::test
normal(refMethod)
val block:()->Unit ={ println("block") }
normal(block)
}
inline fun normal(block:()->Unit){
block.invoke()
}
fun test(){
println("test")
}
输出:
test
block
反编译后,获取类引用时通过创建KFunction接口的子类对象。而Lambda是创建了Function0接口的子类对象。KFunction接口实现了KCallable接口,而Function0接口是Lambda表达式在Java中的实现方式
构造函数的引用
fun main() {
val instance = ::MainFragment.invoke()
}
class MainFragment():Fragment(){
companion object{
fun getInstance()=MainFragment()
}
}
总结
::通过属性 方法 构造函数引用的方式看上去不太好理解。在开发中经常遇到,我们要理解其中的含义。