对比Java学Kotlin接口

Posted 陈蒙_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对比Java学Kotlin接口相关的知识,希望对你有一定的参考价值。

在 Java 中,接口可以看成是抽象类的更进一步抽象,在 Kotlin 中也是这样的。
在 Kotlin 中,接口与抽象类的不同表现在:

  • 用 interface 声明,抽象方法可以省略 abstract 关键字;
  • 成员变量必须是 abstract 的,否则需要提供 get() 方法的实现;

根据上面的描述,我们得知 Kotlin 接口是可以含有普通方法的,这一点是跟 Java 不同的:

interface IFly 
    fun fly() // 省略了 abstract 关键字
    fun accelerate()  // 已经实现的普通方法

在 Kotlin 中,我们不用在像 Java 那样,继承基类使用 extends 关键字、实现接口使用 implements 关键字,徒增记忆负担。在 Kotlin 中我们实现接口的方式也与抽象类是一致的,只需要一个冒号就行了:

class Bird : IFly 
    override fun fly() 

属性

说到属性,这是跟 Java 差别较大的部分。Kotlin 的属性必须是 abstract 的,否则必须提供获取该属性的 get() 方法。这是因为接口中的属性没有影子字段(backing field),无法使用默认的 get() 方法来引用他们。

interface IFly 
    val speed: Int
    val wings: String
        get() = "wings"

    fun fly()


class Bird : IFly 
    override val speed: Int = 30
    override fun fly() 
        TODO("Not yet implemented")
    

继承其他接口

与 Java 一样,Kotlin 中的接口也可以继承其他的接口:

interface Named 
    val name: String


interface Person : Named 
    val firstName: String
    val lastName: String
    override val name: String
        get() = "$firstName $lastName" // name 已经实现了


data class Employee(
    override val firstName: String,
    override val lastName: String,
    val position: Int
) : Person

方法冲突

如果一个类实现了多个接口,多个接口里面有完全相同的方法签名,这时会发生什么?

interface A 
    fun foo() 
        println("A")
    

    fun bar()


interface B 
    fun foo() 
        println("B")
    

    fun bar() 
        println("bar")
    


class C : A 
    override fun bar() 
        println("bar")
    


class D : A, B 
    // 如果不实现该方法,编译器会报错:
    // Class 'D' must override public open fun foo():
    // Unit defined in com.dianping.base.ugc.service.A because it inherits multiple interface methods of it
    override fun foo() 
        super<A>.foo()
        super<B>.foo()
    

    override fun bar() 
        super.bar()
    

接口 A 和 B 里面都有 foo() 和 bar(),二者都实现了 foo(),只有 B 实现了 bar()。
对于 C,很简单,按照规则实现接口的抽象方法 bar() 即可。
比较特殊的是 D,D 同时实现了 A 和 B 两个接口,而且二者中含有相同的方法签名 foo() 和 bar()。这时我们需要把 foo() 和 bar() 都实现才行。

在 Java 中是怎么样的?
首先,Java 中的接口是不能含有已经实现的的方法的。所以 Java 中不存在 Kotlin 中必须要实现接口中已经实现了 foo() 方法的现象。
如果多个接口中含有相同的方法签名,是都要实现的:

public interface A 
    void foo();
    void bar();


public interface B 
    void foo();
    void bar();


public class D implements A, B 
    @Override
    public void foo() 
    
    @Override
    public void bar() 

方法型接口

从 1.4 版本开始,如果一个接口只含有一个抽象方法,我们称这样的接口为方法型接口,或者孤独抽象方法(SAM,single abstract method)。方法型接口里面还可以有多个非抽象方法。
在 Kotlin 中我们使用 fun 修饰符来声明方法型接口:

fun interface KRunnable 
    fun invoke()

SAM 转换

SAM 的好处是,我们可以使用 lambda 表达式来让代码更加简洁和具有更好的可读性。
通常当我们使用接口时,我们需要为接口创建一个对象再使用。而当我们使用 SAM 时,我们可以直接使用 lamdbda 表达式,然后编译器会自动帮我们做转换,把 lambda 表达式转换成对应的对象。
我们有一个 SAM:

fun interface IntPredicate 
    fun accept(i: Int): Boolean

支持情况下我们的使用方法是:

// 创建接口的对象
val isEven = object : IntPredicate 
    override fun accept(i: Int): Boolean 
        return i % 2 == 0
    

借助 SAM 转换,我们可以使用 lambda 表达式来完成:

val isEven = IntPredicate  i -> i % 2 == 0 

对于我们在安卓开发中经常使用的接口,比如 Runnable、OnClickListener 等只含有一个抽象方法的接口,都是可以使用 SAM 转换的:

mButton.setOnClickListener 
    // do something

以上是关于对比Java学Kotlin接口的主要内容,如果未能解决你的问题,请参考以下文章

对比Java学Kotlin接口

对比Java学Kotlin官方文档目录

对比Java学Kotlin枚举

对比Java学Kotlin枚举

对比Java学Kotlin枚举

对比Java学Kotlin嵌套类和内部类