In programming, reflection is a programming language’s ability to inspect and interact with statically defined classes, functions, and properties during runtime.
The feature is particularly useful when you receive an object instance of an unknown class.
By using reflection, you can check if a particular object has a certain method, and call that method when it exists.
To use reflection in Kotlin, you need to include the kotlin-reflect
library in your project:
dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.10")
}
The library contains the runtime component required for using Kotlin reflection features.
Next, let’s see how you can get class, function, and property references using Kotlin reflection feature.
Kotlin reflection - class reference
Suppose you have a Dog
class with the following definitions:
class Dog(var name: String) {
fun bark() {
println("Bark!")
}
fun bark(sound: String) {
println(sound)
}
private fun hello() {
println("Hello! My name is $name")
}
}
To get the class reference in Kotlin, you can use the class literal syntax ::class
as shown below:
val classRef = Dog::class
Alternatively, you can get the class reference from an object instance by using the same ::class
syntax on the instance:
val myDog = Dog("Puppy")
val classRef = myDog::class
Getting the class reference from an object is also known as a bounded class reference.
Once you have the class reference, you can access the properties of the reference to find out more about that class.
For example, you can find the name of the class and check if that class is a data
class:
println(classRef.simpleName) // Dog
println(classRef.qualifiedName) // org.metapx.Dog
println(classRef.isData) // false
In Kotlin, the class reference is identified as the Kclass
type which stands for Kotlin class.
You can check the Kclass
documentation for all properties and methods you can access to find out about the class from its reference.
Aside from inspecting the class, the Kclass
also has some interesting abilities. The createInstance()
method, for example, allows you to create a new object from the class reference:
val secondDog = classRef.createInstance()
But keep in mind that the createInstance()
method only works when the class has a constructor with optional or no parameter.
An error will be thrown when no constructor fulfills the criteria.
Accessing Kotlin class reference methods
You can also get access to the methods of the class reference regardless of their access modifier.
This means even private
functions of a class can be accessed from its reference.
The memberFunctions
property of Kclass
stores all methods of the class as a Collection
:
val myDog = Dog("Puppy")
val classRef = myDog::class
classRef.memberFunctions.forEach {
println(it.name)
}
The output will be as follows:
bark
bark
hello
equals
hashCode
toString
Next, you can call the class function from its reference as follows:
val myDog = Dog("Puppy")
val classRef = myDog::class
val barkRef = classRef.memberFunctions.find {
it.name == "bark"
}
barkRef?.call(myDog)
First, you need to use the find()
function to retrieve the function reference.
Then, check if the function reference is found using the null-safe call.
When the reference is found, use the call()
method from the function reference Kfunction
type.
The first argument of the call()
method must be an instance of the class reference, which is why myDog
object is passed into the method.
When your function is private
, you need to change the isAccessible
property of the function reference as true
first before calling the function:
val helloRef = classRef.memberFunctions.find {
it.name == "hello"
}
helloRef?.isAccessible = true
helloRef?.call(myDog)
And that’s how you access the methods of a class using its reference.
Accessing Kotlin class reference properties
The properties of a Kotlin class reference can be accessed the same way you access its methods.
The properties of a class are stored in memberProperties
as a Collection
.
For example, you can get the name
property value of the myDog
instance as follows:
val myDog = Dog("Puppy")
val classRef = myDog::class
val nameRef = classRef.memberProperties.find {
it.name == "name"
}
println(nameRef?.getter?.call(myDog)) // Puppy
A property reference is an instance of KProperty
type. The value of the property is retrieved by calling the getter()
method.
To change the value of the name
property, you need to cast the property into KMutableProperty
first as shown below:
val myDog = Dog("Puppy")
val classRef = myDog::class
val nameRef = classRef.memberProperties.find {
it.name == "name"
} as KMutableProperty<*>?
nameRef?.setter?.call(myDog, "Jacob")
println(myDog.name) // Jacob
The KMutableProperty
holds the setter()
method, which you need to call to set the value of the property.
Now you’ve learned how to access methods and properties from a class reference.
Next, let’s look at how you can get a function reference with Kotlin reflection
Kotlin reflection - function reference
You can get a reference to a named Kotlin function by using the ::
operator.
Here’s an example:
fun hello() {
println("Hello World!")
}
val funRef = ::hello
funRef() // Hello World!
The funRef
above will be an instance of Kfunction
type, which represents a function with introspection capabilities.
Conclusion
Now you’ve learned what the Kotlin reflection feature is and how it works with some examples. Reflection is a powerful feature that’s only used for specific requirements.
Because of its ability to find inspect a source code, it’s frequently used when developing a framework or library for further development.
JUnit and Spring frameworks are notable for using reflection in their source code.
The library author won’t know the classes and functions created by the user. Reflection allows the framework to deal with classes and functions without knowing about them in advance.