kotlin基础十五:::运算符

112 阅读2分钟

前言

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()
    }
}

总结

::通过属性 方法 构造函数引用的方式看上去不太好理解。在开发中经常遇到,我们要理解其中的含义。