Kotlin Extensions
Kotlin allows for the extension of properties and methods of a class without the need for inheritance or the use of the Decorator pattern.
Extensions are a static behavior and do not affect the code of the class being extended in any way.
Extension Functions
Extension functions can add new methods to an existing class without modifying the original class. The definition format for an extension function is:
fun receiverType.functionName(params){
body
}
receiverType: Indicates the receiver of the function, which is the object being extended.
functionName: The name of the extension function.
params: Parameters of the extension function, can be NULL.
The following example extends the User class:
class User(var name:String)
/**Extension function**/
fun User.Print(){
print("Username $name")
}
fun main(arg:Array<String>){
var user = User("tutorialpro")
user.Print()
}
The output of the example execution is:
Username tutorialpro
The following code is for MutableList:
// Extension function swap, swaps values at different positions
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to this list
this[index1] = this[index2]
this[index2] = tmp
}
fun main(args: Array<String>) {
val l = mutableListOf(1, 2, 3)
// The values at positions 0 and 2 are swapped
l.swap(0, 2) // 'swap()' function's 'this' will point to the value of 'l'
println(l.toString())
}
The output of the example execution is:
[3, 2, 1]
The 'this' keyword refers to the receiver object (that is, the object instance specified before the dot when calling the extension function).
Extension Functions are Static Dispatch
Extension functions are statically dispatched and are not virtual members of the receiver type. When calling an extension function, which function is specifically called is determined by the object expression of the calling function, not by the dynamic type:
open class C
class D: C()
fun C.foo() = "c" // Extension function foo
fun D.foo() = "d" // Extension function foo
fun printFoo(c: C) {
println(c.foo()) // Type is class C
}
fun main(arg:Array<String>){
printFoo(D())
}
The output of the example execution is:
c
If an extension function and a member function are the same, the member function will be used first.
class C {
fun foo() { println("Member function") }
}
fun C.foo() { println("Extension function") }
fun main(arg:Array<String>){
var c = C()
c.foo()
}
The output of the example execution is:
Member function
Extending a Null Object
Inside an extension function, you can use 'this' to determine whether the receiver is NULL. This allows you to call an extension function even if the receiver is NULL. For example:
fun Any?.toString(): String {
if (this == null) return "null"
// After null checking, "this" will automatically convert to a non-null type, so the following toString()
// is resolved as a member function of the Any class
return toString()
}
fun main(arg:Array<String>){
var t = null
println(t.toString())
}
The output of the example execution is:
null
In addition to functions, Kotlin also supports extending properties with properties:
val <T> List<T>.lastIndex: Int
get() = size - 1
Extension properties can be defined in a class or a Kotlin file, but not within a function. Initializer properties are not allowed because properties do not have a backend field (backing field), and can only be defined by explicitly provided getter/setter.
val Foo.bar = 1 // Error: Extension properties cannot have initializers
Extension properties can only be declared as val.
Extension of Companion Object
If a class defines a companion object, you can also define extension functions and properties for the companion object.
The companion object is called in the form of "ClassName.", and the extension functions declared by the companion object are called using the class name as a qualifier:
``` class MyClass { companion object { } // Will be called "Companion" }
fun MyClass.Companion.foo() { println("Extension function of companion object") }
val MyClass.Companion.no: Int get() = 10
fun main(args: Array<String>) { println("no:${My