What is an extension function

Just a word

Extend new functionality without changing existing classes.

Extension functions are not available in Java, but there are specific features in Java that do the same thing, such as inheritance and decorator patterns in design patterns. In terms of functionality, the extension functions in Kotlin are the same, but it comes with Kotlin natively and is much simpler to use.

How should Kotlin’s extension function be used?

Create a generic class DogKt with two existing methods, run() and cry().

class DogKt{
    fun run() = "Dogs can run."
    fun cry() = "Dogs bark."
}
Copy the code

The dog already has two skills: run and bark. Now it needs to extend its ability to follow commands. After the class to be extended, add a method like this:

fun DogKt.order() = "Extended Features -" Dogs follow commands."
Copy the code

With the base classes and extension methods created, if you need to call the dog’s ‘follow instructions’ function, go directly to dogkt.order ().

class DogKt{
    fun run() = "Dogs can run."
    fun cry() = "Dogs bark."
}
fun DogKt.order() = "Extended Features -" Dogs follow commands."

fun main(args: Array<String>) {
    var ex = DogKt()
    println(ex.run())
    println(ex.cry())
    println(ex.order)
}
Copy the code

Results:

Resolution of extension functions is static

The statement that extension functions are resolved to be static means that Kotlin’s extension functions extend the functionality of the class without changing the overall structure of the original class.

For example, the DogKt class will not have an order() method because of the extension of the order() function. The original DogKt class only has two methods, run() and cry(), or only these two methods.

Why do you say so? To verify, we can try to look at the bytecode of the DogKt class using the extension function.

As is obvious in the figure above, in the DogKt classThere are only 1.run(),2.cry() and 3.dogkt constructors.The extended order() is not in the DogKt class.

Extension functions extend the functionality of a class, but the new functionality does not belong to the class, just a reference relationship.

Extension functions do not support polymorphism

We can start by looking at polymorphism in Java

There’s Aninal, which has a run() method, Dog, which has a run() method, and Person, which has a call(Animal Animal).

/ / parent class
public class Animal1 {
    public String run() {
        return "Animal run"; }}/ / subclass
public class Dog extends Animal1 {
    public String run() {
        return "Dog run"; }}// The third call class
public class Person {
    public String call(Animal1 animal1) {
        return animal1.run();
    }
    
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.call(new Animal1()));
        System.out.println(person.call(newDog())); }}Copy the code

Call the run() method on each Animal and Dog instances.

The results for Animal and Dog are printed out. In Java, calling a method depends not on the class declared, but on the instance referenced. For example, in the above example, call(Animal1 Animal1) is Animal, but in fact, if you pass in a Dog instance, you get the result of the Dog class.

The reverse is true in Kotlin’s extension functions, which do not support polymorphism and are called only depending on the declared type of the object.

Again, use Kotlin to write the class in the above example

open class Animal

class Dog : Animal() // Extend the functionfun Animal.run(a)="Animal run"
// Extend the function
fun Dog.run() = "Dog run"

fun person(animal: Animal) {
    println(animal.run())
}

fun main(args: Array<String>) {
    person(Animal())
    person(Dog())
}
Copy the code

As you can see from the above figure, when passed to Animal, it works fine and prints “Animal Run”, but when passed to Dog, it throws a ClassCastException

Exception in thread “main” java.lang.ClassCastException: com.kotlin.Dog cannot be cast to com.kotlin.Animal

Verification shows that extension functions, unlike Java, do not support polymorphism.

Extend the scope of the function

First of all, we need to understand the concepts of two terms: 1: extension receiver, 2: distribution receiver

Extension receiver: an instance of the class to which the extension function extends;

Distribution receiver: Instances of the class in which the extension function is defined are called distribution receivers.

For example,

class Animal1{
    fun run() {
    }

    fun Dog1.call() {
    }
}

class Dog1{
    fun eat(){}}Copy the code

In the Animal1 class, we define an extension function for Dog1 called (), so the Animal class is the distribution receiver, Dog1 is the extension receiver;

The first rule of scope is that extension functions can call both the distribution receiver and the function in the extension receiver, i.e

fun Dog1.call() {
        run()// Distribute the function in the receiver Animal1
        eat()// Extend the function in receiver Dog1
    }
Copy the code

Which class of functions does the extension function call when both the distribution receiver and the extension receiver have a method with the same name?

And double 叒 yi for example.

fun main(args: Array<String>) {
    Animal2().test()
}

class Animal2 {
    fun run() = "is Animal2"

    fun Dog1.call() {
        println(run())
    }

    fun test() {
        Dog1().call()
    }
}

class Dog1 {
    fun run() = "is Dog1"
}

Copy the code

There is a run() in both the Animal2 and Dog1 classes. According to scope 1, the extension function can call both the distribution receiver and the extension receiver, i.e. the function in the Animal2 and Dog1 classes.

Both classes have run, so which class does the extension function call? Let’s verify that.

You can see that the string printed on the console is “is Dogs1”, that is, when the extension function calls a method with the same name in the distribution receiver and the extension receiver, it actually refers to an instance of the extension receiver. This brings us to scope number two:

When a method with the same name exists in both the extension receiver and the distribution receiver, the extension function is called, with the extension receiver taking precedence.