Description: This is the fifth in a series of Kotlin talks on using extension functions in Kotlin to make your code simpler and cleaner. Extension function is a unique new feature in Kotlin language, which can reduce a lot of boilerplate code and greatly improve the efficiency of development. It is also very simple to use extension functions. I’ll explain extension functions in Kotlin in the following ways.

  • 1. Why use extension functions in Kotlin?
  • 2. How to use extension functions and extension attributes?
  • 3. What are extension functions and attributes?
  • 4. The difference between extension functions and member functions
  • 5. Extension functions cannot be overridden

Why use extension functions in Kotlin

We all know that Koltin has excellent interoperability with Java, so the new feature of extension functions can be smoothly integrated with existing Java code. Even pure Kotlin projects can be built on Java libraries, or even some framework libraries in Android, third-party libraries. Extension functions are well suited to the Kotlin and Java language hybrid development pattern. At many companies, some of the more stable libraries are written in Java, and there is no need to rewrite them in Kotlin. However, if you want to extend the library’s interface and functionality, extension functions may come in handy. Another benefit of using Kotlin’s extension functions is that there are no side effects, and no changes to the original library code or functionality. So let’s see what the extension function looks like

  • TextView bold simple example
// Extend the function definition
fun TextView.isBold(a) = this.apply { 
	paint.isFakeBoldText = true
}

// Extend the function call
activity.find<TextView>(R.id.course_comment_tv_score).isBold()
Copy the code

How to use extension functions and extension attributes

  • 1. Basic use of extension functions

Simply place the name of the extended class or interface in front of the name of the function to be added. This class or name is called the receiver type, and the connection between the class name and the function is called with a “.”. This refers to the receiver object, which has access to methods and properties accessible by the extended class.

Note: The receiver type is defined by the extension function, and the receiver object is the object instance of the receiver type. The object instance has access to the member methods and attributes of the class, so the extension function is usually used as a member function.

  • 2, extended attributes the basic use of extended attributes, in fact, is to provide a method to access the attributes, and the extended attributes from any state, because it is impossible to add additional properties of objects in the existing Java library field, just use concise syntax similar to directly manipulate attributes, in fact or method of access.
// Extend the attribute definition
var TextView.isBolder: Boolean
	get() {// The get() method must be defined because you cannot add fields to existing objects, and there is no default implementation of get()
		return this.paint.isFakeBoldText
	}
	set(value) {
		this.paint.isFakeBoldText = value
	}
// Extend the attribute call
activity.find<TextView>(R.id.course_comment_tv_score).isBolder = true
Copy the code

Note:

  • An extension attribute, like an extension function definition, also has a receiver type and a receiver object, which is an instance of the receiver type and can be used as a member attribute in a class.

  • The get() method must be defined. In Kotlin, attributes in classes add get() by default, but since extending attributes does not add additional attributes to existing library classes, there is no such thing as default get() implementation. So you have to add the get() method manually.

  • The override of the set() method means that the property access is readable and writable, requiring var

What are extension functions and attributes

As we can see from the above example, Kotlin’s extension function is really powerful. It can add properties and methods to existing library classes without any side effects. In the TextView example, we did not touch the TextView source code at all, but added an extension property and function to it. Has so powerful function, after all what is the principle behind it? Decompile shows the decomcompiled Java code.

  • 1, the essence of extension function principle

An extension function is essentially a Java static function that takes an object of the receiver type, accesses the member properties and methods of the class, and returns the receiver type object itself. This has the same external feel as using the class’s member functions.

public final class ExtendsionTextViewKt {// This class name is the top-level filename + "Kt" suffix, which was explained in detail in the previous blog post
   @NotNull
   public static final TextView isBold(@NotNull TextView $receiver) {// The extension function isBold corresponds to what is actually a static function in Java and takes a receiver type object as an argument
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      $receiver.getPaint().setFakeBoldText(true);// Set bold
      return $receiver;// Finally returns the receiver object itself, so that in Kotlin we could have used this instead of the receiver object or not.}}Copy the code
  • 2. Call extension functions defined in Kotlin in Java

After we analyze the principle of the Kotlin extension function, we also know how to call the Kotlin extension function in Java. In fact, the method is static function call, which is similar to the top-level function call in Java, but the difference is that you need to pass in a receiver object parameter.

ExtendsionTextViewKt.isBold(activity.findViewById(R.id.course_comment_tv_score));// Call static functions directly
Copy the code
  • 3. Principle of extended attribute essence

An extended property is actually a set or get method that provides access to a property. The two sets of get methods are static functions that pass in an object of type receiver and then use the object instance inside to access and modify the property of the corresponding class of the object.

public final class ExtendsionTextViewKt {
   // The get() method generates a static function and passes an object of type receiver as an argument
   public static final boolean isBolder(@NotNull TextView $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      return $receiver.getPaint().isFakeBoldText();
   }
   // The set() method generates a static function and passes in an object of type receiver as an argument and an argument that needs to be set
   public static final void setBolder(@NotNull TextView $receiver, boolean value) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      $receiver.getPaint().setFakeBoldText(true); }}Copy the code
  • 4. Call the extended properties defined in Kotlin in Java

Java calls to the extended properties defined in Kotlin are as simple as directly calling the generated set(),get() methods.

    ExtendsionTextViewKt.setBolder(activity.findViewById(R.id.course_comment_tv_score), true);
Copy the code

Fourth, the difference between extension function and member function

The difference between an extension function and a member function is already clear from the above example. Here’s a summary:

  • 1. Extension functions and member functions are used in a similar manner, allowing direct access to the methods and attributes of the extended class. (Principle: an object passed an extension class is actually used to access the methods and attributes of the extension class.)
  • 2. Extension functions cannot break the encapsulation of extension classes and cannot directly access internal private functions and attributes like member functions. (Principle: The principle is simple: extension function access is actually the object access of the class. Since the object instance of the class cannot access the internal private functions and attributes, the natural extension function cannot access the internal private functions and attributes.)
  • An extension function is actually a static function outside of a class, while a member function is an internal function of a class.
  • 4. Superclass member functions can be overridden by subclasses, but extension functions cannot

Extension functions cannot be overridden

In Kotlin and Java we know that member functions of a class can be overridden, and that subclasses can override member functions of their parent class, but subclasses cannot override extension functions of their parent class.

open class Animal {
    open fun shout(a) = println("animal is shout")// Define member functions
}

class Cat: Animal() {
    override fun shout(a) {
        println("Cat is shout")// Subclasses override parent member functions}}// Define subclass and superclass extension functions
fun Animal.eat(a) = println("Animal eat something")

fun Cat.eat(a)= println("Cat eat fish")

/ / test
fun main(args: Array<String>) {
    val animal: Animal = Cat()
    println("Member function test:${animal.shout()}")
    println("Extended function test:${animal.eat()}")}Copy the code

Running results:

Once again, extension functions are not part of the class. They are declared outside the class. Although subclasses and superclasses have the same extension function, extension functions are actually static. Internally, the subclass and the parent class have the same extension function. In effect, we define two static extension functions with the same name as the parent object and the subclass object. Then the method called must also be the method in the parent class and the method in the subclass, so the output must be the parent class.

Welcome to the Kotlin Developer Association, where the latest Kotlin technical articles are published, and a weekly Kotlin foreign technical article is translated from time to time. If you like Kotlin, welcome to join us ~~~