Class reference
The most basic reflection function is to get the runtime reference of Kotlin class. To get a reference to a statically known Kotlin class, you can use class literal syntax
val c = MyClass::class
Note that Kotlin class references are different from java class references. To get a java class reference, use on the KClass instance java properties
Bound class reference (since 1.1)
By using the object as the receiver, you can get the reference of the class of the specified object with the same:: class syntax
val widget: Widget = ...... assert(widget is GoodWidget) { "Bad widget: ${widget::class.qualifiedName}" }
You can get a reference to the exact class of the object, such as GoodWidget or BadWidget, although the type of receiver expression is Widget
Callable reference
In addition to being a introspective program structure, function attributes and constructor references can also be used for calling or as instances of function types.
The public supertype of all callable references is kcallable < out R >, where R is the return value type, attribute type for attribute and constructed type for constructor
Function reference
When we have a named function declared as follows
fun isOdd(x: Int) = x % 2 != 0
We can easily call it directly (isOdd(5)), but we can also pass it as a value of a function type, for example, to another function. To do this, we use the:: operator
val numbers = listOf(1, 2, 3) println(numbers.filter(::isOdd))
Function reference belongs to one of the subtypes of kfunction < out R > and depends on the number of parameters. For example, kfunction3 < T1, T2, T3, R >.
When the type expected by the function is known in the context,:: can be used to overload the function. for example
fun isOdd(x: Int) = x % 2 != 0 fun isOdd(s: String) = s == "brillig" || s == "slithy" || s == "tove" val numbers = listOf(1, 2, 3) println(numbers.filter(::isOdd)) // Reference to isOdd(x: Int)
Alternatively, you can provide the necessary context by storing the method reference in a variable with an explicitly specified type
val predicate: (String) -> Boolean = ::isOdd // Reference to isOdd(x: String)
If we need to use the member function or extension function of the class, it needs to be qualified, such as String::toCharArray.
Note that even if a variable is initialized with a reference to an extended function, the inferred function type will have no receiver (it will have an additional parameter that accepts the receiver object). If you need to change to the function type with receiver, please specify its type explicitly
val isEmptyStringList: List<String>.() -> Boolean = List<String>::isEmpty
Example: function combination
Consider the following functions
fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C { return { x -> f(g(x)) } }
It returns a combination of two functions passed to it: compose(f, g) = f(g(*)). Now you can apply it to callable references
fun length(s: String) = s.length val oddLength = compose(::isOdd, ::length) val strings = listOf("a", "ab", "abc") println(strings.filter(oddLength))
Attribute reference
To access attributes as first-class objects in Kotlin, we can also use the:: operator
val x = 1 fun main() { println(::x.get()) println(::x.name) }
The expression:: x evaluates to an attribute object of type kproperty < int >, which allows us to use get() to read its value, or use the name attribute to get the attribute name
For variable attributes, such as var y = 1,:: y returns a value of kmutableproperty < int > type, which has a set() method
var y = 1 fun main() { ::y.set(2) println(y) }
Property references can be used where a function with a single generic parameter is expected
val strs = listOf("a", "bc", "def") println(strs.map(String::length))
To access a property belonging to a member of a class, we qualify it this way
class A(val p: Int) val prop = A::p println(prop.get(A(1)))
For extended properties
val String.lastChar: Char get() = this[length - 1] fun main() { println(String::lastChar.get("abc")) }
Interoperability with Java reflection
import kotlin.reflect.jvm.* class A(val p: Int) fun main() { println(A::p.javaGetter) // Output "public final int A.getP()" println(A::p.javaField) // Output "private final int A.p" }
To get the kotlin class corresponding to the Java class, use Kotlin extended properties
fun getKClass(o: Any): KClass<Any> = o.javaClass.kotlin
Constructor reference
Constructors can be referenced like methods and properties. They can be used anywhere a function type object is expected: it takes the same parameters as the constructor and returns an object of the corresponding type. Reference the constructor by using the:: operator and adding the class name. Consider the following function, which expects a function parameter that has no parameters and returns Foo type
class Foo fun function(factory: () -> Foo) { val x: Foo = factory() }
Using:: Foo, the zero parameter constructor of class Foo, we can simply call it
function(::Foo)
The callable reference type of the constructor is also one of the subtypes of kfunction < out R >, depending on the number of its parameters
Bound function and property references (since 1.1)
You can reference instance methods of specific objects
val numberRegex = "\\d+".toRegex() println(numberRegex.matches("29")) val isNumber = numberRegex::matches println(isNumber("29"))
Instead of calling method matches directly, we store its references. Such a reference is bound to its recipient. It can be called directly (as shown in the above example) or used whenever a function type expression is expected
val numberRegex = "\\d+".toRegex() val strings = listOf("abc", "124", "a70") println(strings.filter(numberRegex::matches))
Compare the bound type with the reference of the corresponding unbound type. A bound callable reference has its receiver "attached" to it, so the receiver's type is no longer a parameter
val isNumber: (CharSequence) -> Boolean = numberRegex::matches val matches: (Regex, CharSequence) -> Boolean = Regex::matches
Property references can also be bound
val prop = "abc"::length println(prop.get())
Since Kotlin 1.2, there is no need to explicitly specify this as the receiver: this::foo is equivalent to:: foo
Bound constructor reference
The callable reference of the binding of the constructor of the inner class can be obtained by providing an instance of the external class
class Outer { inner class Inner } val o = Outer() val boundInnerCtor = o::Inner