Kotlin abstraction and interface

Kotlin abstraction and interface

In fact, most of the inheritance and interfaces in Kotlin are the same as Java, but the support at the grammatical level is different. Because Kotlin will have a layer of syntactic sugar that can easily and efficiently declare a certain grammar, allowing you to focus more on business logic instead of grammatical code templates. Then we will talk about the implementation of multiple inheritance in Kotlin. Kotlin and Java are both single inheritance. This is unquestionable, but we will also need multiple inheritance scenarios. So how does Kotlin solve such scenarios? Everyone must be thinking of multiple inheritance of interfaces. Let's take a look at how to take a look.

1. Abstraction and Interface

Like Java, Kotlin also uses  abstract and  interface to declare abstract classes and interfaces separately. In addition, Kotlin's interfaces also support the implementation of non-abstract methods (this is very similar to the default method in Java8), but you need to pay attention to the internals. Any state (in the form of a pure function).

1.1 Abstract class declaration

In Kotlin, the declaration of abstract classes uses  abstract keywords, and the methods in abstract classes use the  abstract declarative abstract methods.

//以Random.kt源码为例
public abstract class Random {//使用abstract关键声明一个抽象类Random
    public abstract fun nextBits(bitCount: Int): Int //与Java一样使用abstract声明一个抽象类中抽象方法,所以子类必须要实现该方法
    
    public open fun nextInt(): Int = nextBits(32)//open表示这个类可以被子类重写

    public fun nextInt(until: Int): Int = nextInt(0, until)//由于Kotlin默认是final且没有显式open,所以该方法不能被子类重写
    ...
}

1.2 Interface statement

The interface declaration in Kotlin uses  interface keywords:

interface OnClickListener {//使用interface关键字声明一个接口
    fun onClick() //声明了一个接口抽象方法,所有实现这个接口的非抽象类都需要实现这个方法
}

Implement a simple interface in Kotlin

class Button: OnClickListener {
   override fun onClick() = println("Button is Clicked") //与Java不同的是在Kotlin中override必须是强制要求的
}

2. Interfaces with default methods in Kotlin

We all know that in the following versions of Java 8, there can be no implementation method in the interface. Until there are  default methods in Java 8, then methods with implementation can be declared in Java 8.

//java8实现
public interface OnClickListener {
    public void onClick();
    
    default public void onClickLog() {//使用default关键字声明接口中一个带实现的方法,这个Java8以下版本是无法做到
       System.out.println("clicked!");
    }
}

We have seen how to implement interfaces with default methods in Java 8, but how is it done in Kotlin? In fact, Kotlin syntax naturally supports methods with default implementations, and there is no need to add any keywords or modifiers.

//kotlin实现
interface OnClickListener {
    fun onClick()
    fun onClickLog() = println("clicked!")//不需要声明任何关键字,直接支持带默认实现的方法
}

Then the question is coming. We all know that Kotlin is fully compatible with Java6. However, this interface method with default implementation is not supported under Java8. So how does Kotlin make it compatible with this grammatical feature in versions below Java8? Decompile its Kotlin code at a glance.

//反编译后java代码
public interface OnClickListener {
   void onClick();

   void onClickLog();

   @Metadata(
      mv = {1, 1, 16},
      bv = {1, 0, 3},
      k = 3
   )
   public static final class DefaultImpls {//可以看到这边自动生成一个DefaultImpls静态类
      public static void onClickLog(OnClickListener $this) {//默认实现方法onClickLog被声明成一个静态方法
         String var1 = "Clicked!";
         boolean var2 = false;
         System.out.println(var1);
      }
   }
}

Maybe you see the above code is not very intuitive, and you don't know how it triggers the  DefaultImpls call, so we can add the above code to an implementation class to see how it is called.

package com.imooc.test

interface OnClickListener {
    fun onClick()

    fun onClickLog() = println("Clicked!")
}

class Button : OnClickListener {//Button实现类
    override fun onClickLog() {//重写onClickLog方法
        super.onClickLog()//默认通过super调用父类默认实现的方法
    }

    override fun onClick() {

    }
}

Decompiled Java code

// OnClickListener.java
public interface OnClickListener {
   void onClick();

   void onClickLog();

   @Metadata(
      mv = {1, 1, 16},
      bv = {1, 0, 3},
      k = 3
   )
   public static final class DefaultImpls {
      public static void onClickLog(OnClickListener $this) {
         String var1 = "Clicked!";
         boolean var2 = false;
         System.out.println(var1);
      }
   }
}
// Button.java
public final class Button implements OnClickListener {
   public void onClickLog() {
      OnClickListener.DefaultImpls.onClickLog(this);//现在可以看到实际上通过接口类名调用它内部静态类DefaultImpls,再通过静态类DefaultImpls调用它的静态方法onClickLog
   }

   public void onClick() {
   }
}

So to sum up, how Kotlin interface in the default implementation is compatible with the following versions of Java8 , it is actually in the internal interface generates a static class  DefaultImpls , and generate a corresponding default implementation of internal static method in a static class . Then you only need to pass the interface name when calling. Static class  DefaultImpls . The default implementation of static method name call can be.

3. Multiple inheritance of interfaces in Kotlin

We all know that multiple inheritance is not supported in Java, but Kotlin also does not support multiple inheritance of classes. But why is it designed like this, but I believe that many small partners should have had this feeling, and they still encounter multiple inheritance scenarios in normal development.

3.1 Why not support multiple inheritance of classes

I believe everyone is aware of the classic multiple inheritance problem, commonly known as the "diamond inheritance problem". We use the contradiction method, assuming that Java/Kotlin supports multiple inheritance of classes, let’s take a look at an example. There is an invoke method in class A. Both classes B and C inherit class A, and then class D inherits class B separately. , Class C.

abstract class A {
   abstract fun invoke()
}

class B: A {
   override fun invoke() = println("B invoke")
}

class C: A {
   override fun invoke() = println("C invoke")
}

class D: B,C {//假设支持类的多继承
    override fun invoke() = println("C invoke")// B ? C
}

image description

So the question is, should class D inherit the invoke method of class B or the invoke method of class C? Therefore, multiple inheritance of such classes can easily lead to ambiguity.

But we know that the problem of multiple inheritance may still be encountered in the development process. Our commonly used method is to use interface multiple inheritance to solve it, because we know that multiple inheritance of interfaces is supported in Java and Kotlin.

3.2 Multiple inheritance of interfaces in Kotlin

Interface multiple inheritance is supported in Java, and Kotlin still supports it. So let's take a look at how to solve the above-mentioned multiple inheritance problem in Kotlin?

package com.imooc.test

interface A {
    fun invoke()
}

interface B : A {
    override fun invoke() {
        println("B invoke")
    }
}

interface C : A {
    override fun invoke() {
        println("C invoke")
    }
}

class D : B, C {
    //override fun invoke() = super<B>.invoke()//通过super中泛型类型指定继承B接口的方法,所以最后输出"B invoke"
    override fun invoke() = super<C>.invoke()//通过super中泛型类型指定继承C接口的方法,所以最后输出"C invoke"
}

fun main() {
    val d = D()
    d.invoke()
}

4. Summary

This is the end of the abstraction and interface in Kotlin. In fact, the abstraction and interface in Kotlin are basically similar to those in Java. Just pay attention to the differences mentioned in the article.

 

Guess you like

Origin blog.csdn.net/PrisonJoker/article/details/114108234