Before the order

When using reflection in Kotlin, you are dealing with two different reflection apis.

  • Standard Java reflection, defined in packagesjava.lang.reflectIn the. Because Kotlin classes are compiled into plain Java bytecode, the Java reflection API supports them perfectly.
  • Kotlin reflection API, defined in the packagekotlin.reflectIn the. The Kotlin Reflection API gives you access to concepts that don’t exist in the Java world, such as properties and nullable types. The Kotlin Reflection API is not an alternative to the Java Reflection API. Meanwhile, the Kotlin reflection API is not limited to Kotlin classes; classes written in any JVM language can be accessed using the same API.

Class reference

The most basic reflection function is to get a runtime reference to the Kotlin class.

val daqiKotlinClass = daqiKotlin::class
Copy the code

Kotlin’s class reference is actually a value of type KClass. If you want to get a Java class reference, you can use.java property retrieval on a KClass instance.

For a Java class reference, you can convert it to a Kotlin class reference using. Kotlin

val daqiKotlinJavaClass = daqiKotlin::class.java
val daqiKotlinaClass = daqiKotlinJavaClass.kotlin
Copy the code
Properties or functions meaning
memberProperties Non-extended attributes declared in this class and all of its superclasses
memberFunctions Non-extended non-static functions declared in this class and all of its superclasses
members Non-extended non-static functions and properties declared in this class and all of its superclasses, excluding constructors
constructors All constructors
isFinal Final class
isOpen Class open
isAbstract Abstract class
isSealed Is it sealed?
isData Data class
isInner Inner class
isCompanion Whether it is an associated object

Introduce Kotlin reflection

On the Java platform, the runtime components required to use reflection are distributed as separate JAR files (kotlin-reflect.jar). This is done to reduce the size of the runtime libraries required by applications that do not use reflection. If you need to use reflection, make sure the.jar file is added to your project’s classpath.

Add the Kotlin reflection JAR to Gradle (see here) :

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"// Add Kotlin reflection JAR package implementation"org.jetbrains.kotlin:kotlin-reflect"
    testImplementation "org.jetbrains.kotlin:kotlin-test"
    testImplementation "org.jetbrains.kotlin:kotlin-test-junit"
}
Copy the code

KCallable

In Kotlin’s class reference KClass, attributes and functions are stored in the KCallable collection Members, while constructors are stored in the KFunction collection Constructors. The superinterface of KFunction is KCallable, that is, KCallable is the superinterface of functions (including constructors) and attributes.

KCallable declares the call method, which allows you to call the corresponding function or the getter for the corresponding property:

public actual interface KCallable<out R> : KAnnotatedElement { public fun call(vararg args: Any?) : R ..... }Copy the code

Function KFunction

When we learned about lambda, we learned about method references, which use the :: operator to refer to methods and return a KFunction object.

For KFunction objects, the KCallable#call method can be used to call the referenced function. But ::daqi is also an object of type KFunctionN (N stands for a specific number of arguments, similar to lambda’s Function), and the reference Function can be called via the invoke method. (Since the invoke method is an Openator method, the convention can use () instead to call the invoke method)

fun main(){
    val func = ::daqi
    func.invoke("")
    func.call("")
}

fun daqi(name:String){
}
Copy the code

The difference between KCallable#call and KFunctionN#invoke is that the parameter type and return value type of KFunctionN#invoke are determinable and can be checked by the compiler. If the argument type and number do not match invoke, the compiler will not compile. KCallable#call is valid for all types, which means that the developer needs to match the corresponding argument type and number, otherwise it will get an exception at runtime.

Each KFunctionN type inherits KFunction with an additional invoke with just the right number of arguments. For example: KFunction2 declares Openator Fun Invoke (P1 :P1, P2 :P2):R. The KFunctionN types are synthesized compiler-generated types and their declarations cannot be found in the package kotlin.reflect. Means a function interface that can use any number of parameters.

Attribute KProperty

KProperty differs from Java’s Field, which generally refers to the Field itself, in that it stands for the corresponding Getter and Setter.

KProperty can represent any property, and its subclass, KMutableProperty, can represent a variable declared by var.

The supertype of KProperty is also KCallable, meaning that when you get the property, you can also use KCallable# Call, which calls the getter for the property. But Kotlin’s attribute interface provides a better way to get attribute values: the get method.

  • KProperty0<out R>Provided is a no-parametergetMethod whose type parameter represents the type of the property;

Top-level attributes, for example, are referenced directly using the :: operator. Because the receiver is not required, the property reference is of type KProperty0.

val name = "daqi"

fun main(){
    val property = ::name
    property.get()
    property.call()
}
Copy the code
  • KProperty1<T, out R>Provide one that requires a receivergetMethod, where one type parameter represents the type of the receiver and the second type parameter represents the type of the property;

For example, a member property or an extended property requires a concrete recipient instance whose property reference is of type KProperty1

fun main(){
    val property = daqiKotlin::name
    val daqi = daqiKotlin()
    property.get(daqi)
}

class daqiKotlin{
    val name = ""
}
Copy the code

Attribute references can only be used to define attributes in an outer layer or class, not local variables.

As a subclass of KProperty, KMutableProperty provides a set method in addition to the corresponding GET method.

fun main(){
    val property = daqiKotlin::name
    val daqi = daqiKotlin()
    property.get(daqi)
    property.set(daqi,"")
    property.call(daqi)
}

class daqiKotlin{
    var name = ""
}
Copy the code

The call method of a KMutableProperty instance is still the getter that calls that property.

The last

The Kotlin Basics series concludes with this chapter. Along the way, I have clarified many of the concepts myself, and the Kotlin basics have become more solid. At the same time, I also know that MY writing style is rough, and I will improve step by step in the future to make it easier for readers to understand the content of the article.

Here are three excellent Kotlin articles:

  • Exploring hidden Costs in Kotlin (Part I)
  • Exploring hidden Costs in Kotlin (Part II)
  • Exploring Kotlin’s Hidden Costs (Part 3)

References:

  • Kotlin in Action
  • Kotlin website

Android Kotlin series:

Kotlin’s Knowledge generalization (I) — Basic Grammar

Kotlin knowledge generalization (2) – make functions easier to call

Kotlin’s knowledge generalization (iii) — Top-level members and extensions

Kotlin knowledge generalization (4) – interfaces and classes

Kotlin’s knowledge induction (v) — Lambda

Kotlin’s knowledge generalization (vi) — Type system

Kotlin’s knowledge induction (7) — set

Kotlin’s knowledge induction (viii) — sequence

Kotlin knowledge induction (ix) — Convention

Kotlin’s knowledge induction (10) — Delegation

Kotlin’s knowledge generalization (xi) — Higher order functions

Kotlin’s generalization of knowledge (xii) – generics

Kotlin’s Generalization of Knowledge (XIII) — Notes

Kotlin’s Knowledge induction (xiv) — Reflection