“This is the 8th day of my participation in the First Challenge 2022. For details: First Challenge 2022”
preface
Moving on to reflection, Class may be familiar to Java developers, but that’s fine if you’re not, let’s take a look at Kotlin’s reflection Class: KClass.
As for what reflection is, check out the previous article:
# Kotlin reflection full resolution 1 — Basic concept
The body of the
KClass is basically the Kotlin version of Class, but I personally think it has a better API design.
Overview and acquisition of KClass
This KClass is the main Kotlin reflection class, so let’s look at the source code comment:
/ / KClass annotations
Represents a class and provides introspection capabilities. Instances of this class are obtainable by the: :class syntax. See the Kotlin language documentation for more information.
Params:
T - the type of the class.
Copy the code
- Indicates that a class has introspection, and instances of that class can then be obtained using the ::class syntax.
I think the introspection here is very good, which is that you can get information about this class through KClass.
Let’s go straight to an example:
// Define a class directly
class MainActivity : AppCompatActivity(a){
// Private member variables
private val privateInt = 10
// Member variables
val norInt = 10
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
testFunction()
}
fun testFunction() {
// Get the KClass of the class
val kClass = MainActivity::class// Get member information for printingkClass.memberProperties.forEach {
println("memberProperties $it")}}}Copy the code
Then you’ll find this print:
2022-01-22 15:17:47.127 7832-7832/com.wayeal.testgit I/System.out: memberProperties val com.wayeal.testgit.MainActivity.norInt: kotlin.Int
2022-01-22 15:17:47.128 7832-7832/com.wayeal.testgit I/System.out: memberProperties val com.wayeal.testgit.MainActivity.privateInt: kotlin.Int
Copy the code
You’ll find that you can print out two properties of the MainActivity class.
Now that we’re talking about the memeberProperties method, let’s see what it is:
val <T : Any> KClass<T>.memberProperties: Collection<KProperty1<T, *>>
get() = (this as KClassImpl<T>).data().allNonStaticMembers.filter {
it.isNotExtension && it is KProperty1<*, *> } as Collection<KProperty1<T, *>>
Copy the code
It is an extension function of KClass, and is filtered only if the member is of type KProperty1 and not an extension function.
KClass structure
Now that you know that reflection is about retrieving information about a class, and Kotlin stores that information in KClass, you must familiarize yourself with the KClass structure and look directly at the source code:
// Implement 3 interfaces
public actual interface KClass<T : Any> : KDeclarationContainer, KAnnotatedElement, KClassifier {
// Simple name
public actual val simpleName: String?
// Full name of the class
public actual val qualifiedName: String?
Class and all attributes and methods defined by its parent class
// The type is KCallable
override val members: Collection<KCallable<*>>
// All constructors
// type KFunction
public val constructors: Collection<KFunction<T>> // All classes defined internally, including inner classes and statically nested classespublic val nestedClasses: Collection<KClass<*>> // Type parameter of the class, that is, type parameter of the generic classpublic val typeParameters: List<KTypeParameter> // A list of the direct parent types of the classpublic val supertypes: List<KType> // If this class is a sealed class, get all of its subclassespublic val sealedSubclasses: List<KClass<out T>> // The visible modifier for this class, that isPUBLIC PROTECTAnd so on 4 casespublic val visibility: KVisibility? / / whetherfinal.KotlinThe default class isfinal, cannot inheritpublic val isFinal: Boolean/ / whetherOpen, andisFinalIn turn,public val isOpen: Boolean// Is an abstract classpublic val isAbstract: Boolean// Whether the class is sealed @SinceKotlin("1.1")
public val isSealed: Boolean// Is a data classpublic val isData: Boolean// Is an inner classpublic val isInner: Boolean// Is an associated objectpublic val isCompanion: Boolean// Whether the class is oneKotlinThe function interfacepublic val isFun: Boolean/ / whethervalue classThis is new in 1.5public val isValue: Boolean
}
Copy the code
The KClass interface here adds a lot of Kotlin’s own methods, such as whether it’s a class interface.
In fact, these methods do not need to memorize, you can think about your usual definition of a class, it contains what content, my personal analysis can be divided into the following aspects:
-
Class name, this pair should have the corresponding API to get the simple class name and full class name.
-
Visible modifiers are nothing more than public, protected, internal, and private.
-
Kotlin is final by default.
-
In the case of a generic class, its type parameter.
-
The parent class that it inherits or implements.
-
Its inner class or nested class.
In addition to the above, there are the following highlights:
-
The properties and methods of this class, which Kotlin considers subclasses of KCallable, are returned in members. We’ll talk more about this class later.
-
Constructors, I’m going to mention constructors separately, because it’s a special method.
KClass extension function
The KClass API is designed to be fairly easy to understand, but it can be a little confusing. For example, in KClass, members returns all the methods and attributes of the parent class and the current class. That’s not a good idea. In Java, there are different apis to distinguish between the two cases. In Kotlin, there are some extension functions designed to distinguish between the two cases.
//KClass extension function
// Return the primary constructor of the class. No primary constructor returns NULL
val <T : Any> KClass<T>.primaryConstructor: KFunction<T>?
get() = (this as KClassImpl<T>).constructors.firstOrNull {
((it as KFunctionImpl).descriptor as ConstructorDescriptor).isPrimary
}
// Returns the associated object instance, or null if none is present
val KClass<*>.companionObject: KClass<*>?
get() = nestedClasses.firstOrNull {
(it as KClassImpl<*>).descriptor.isCompanionObject
}
// Returns the associated object instance, otherwise null
val KClass<*>.companionObjectInstance: Any?
get() = companionObject?.objectInstance
// Return attributes and methods defined by the class, not counted in the parent class
val KClass<*>.declaredMembers: Collection<KCallable<*>>
get() = (this as KClassImpl).data().declaredMembers
// Returns all functions of the class and its parent, including static functions
val KClass<*>.functions: Collection<KFunction<*>>
get() = members.filterIsInstance<KFunction<*>>()
// Returns a static function in this class
val KClass<*>.staticFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl).data().allStaticMembers.filterIsInstance<KFunction<*>>()
// Returns all member functions of the class and its parent, i.e., non-extended, non-static functions
val KClass<*>.memberFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl).data().allNonStaticMembers.filter { it.isNotExtension && it is KFunction<*> } as Collection<KFunction<*>>
// Returns all extension functions for the class and its parent
val KClass<*>.memberExtensionFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl).data().allNonStaticMembers.filter { it.isExtension && it is KFunction<*> } as Collection<KFunction<*>>
// Returns all functions of the class
val KClass<*>.declaredFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl).data().declaredMembers.filterIsInstance<KFunction<*>>()
// Returns a non-static, non-extended function in this class
val KClass<*>.declaredMemberFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl).data().declaredNonStaticMembers.filter { it.isNotExtension && it is KFunction<*> } as Collection<KFunction<*>>
// Returns an extension function for that class
val KClass<*>.declaredMemberExtensionFunctions: Collection<KFunction<*>>
get() = (this as KClassImpl).data().declaredNonStaticMembers.filter { it.isExtension && it is KFunction<*> } as Collection<KFunction<*>>
// Returns the static property of the class
val KClass<*>.staticProperties: Collection<KProperty0<*>>
get() = (this as KClassImpl).data().allStaticMembers.filter { it.isNotExtension && it is KProperty0<*> } as Collection<KProperty0<*>>
// Returns all non-extended attributes of the class and its parent
val <T : Any> KClass<T>.memberProperties: Collection<KProperty1<T, *>>
get() = (this as KClassImpl<T>).data().allNonStaticMembers.filter { it.isNotExtension && it is KProperty1<*, *> } as Collection<KProperty1<T, *>>
// Returns the extended attributes of the class and its parent
val <T : Any> KClass<T>.memberExtensionProperties: Collection<KProperty2<T, *, *>>
get() = (this as KClassImpl<T>).data().allNonStaticMembers.filter { it.isExtension && it is KProperty2<*, *, *> } as Collection<KProperty2<T, *, *>>
// Returns a non-extended attribute in this class
val <T : Any> KClass<T>.declaredMemberProperties: Collection<KProperty1<T, *>>
get() = (this as KClassImpl<T>).data().declaredNonStaticMembers.filter { it.isNotExtension && it is KProperty1<*, *> } as Collection<KProperty1<T, *>>
// Returns the extended attribute of the class
val <T : Any> KClass<T>.declaredMemberExtensionProperties: Collection<KProperty2<T, *, *>>
get() = (this as KClassImpl<T>).data().declaredNonStaticMembers.filter { it.isExtension && it is KProperty2<*, *, *> } as Collection<KProperty2<T, *, *>>
// Create an instance using either the null argument constructor or the full argument constructor
@SinceKotlin("1.1")
fun <T : Any> KClass<T>.createInstance(): T {
// TODO: throw a meaningful exception
val noArgsConstructor = constructors.singleOrNull{ it.parameters.all(KParameter::isOptional) } ? :throw IllegalArgumentException("Class should have a single no-arg constructor: $this")
return noArgsConstructor.callBy(emptyMap())
}
Copy the code
The following methods are easier to understand and remember than the Java API (see modifiers). For example, methods classified as classes or those containing their parent can be named using declared or extensions (see modifiers). Functions are distinguished by functions and Properties by Properties.
conclusion
Of course, there is only a brief overview here. For example, if I want to obtain the properties or methods, that is the use of KFunction and KProperty. We will continue in the next article.