Kotlin基础七:接口

99 阅读3分钟

前言

由于语法上的差异Kotlin中的接口和Java的接口有一些区别的。多个父接口 接口的继承 属性定义 接口默认实现等

接口

使用关键字interface定义

interface Call{}

Kotlin中声明抽象方法可以包含抽象方法的实现。

interface Call{
    fun onCall()
}
class A:Call{}// 报红
interface Call{
    fun onCall(){
        println("onCall")
    }
}
class A:Call{}// 给接口添加了默认的实现后,编译通过

在Androidstudio打开Tools->Kotlin->Show->Kotlin Bytecode点击Decompile按钮 Call接口默认帮我们声明了静态内部类DefaultImpls,声明了同名的静态方法onSuccess,有onCall的具体实现,而A类也帮我们默认实现了oncall抽象方法,通过调用DefaultImpls中的同名方法来完成具体的实现

interface Call{
    fun onCall(){
        println("onCall")
    }
}

在其实现类中默认实现了抽象方法,不需要每个子类都去显示的实现接口中的抽象方法,我们可以采用这种默认的实现方式。

接口中的属性

接口中定义的属性都是抽象的,和方法一样都可覆盖。我们可以为其提供访问器get和set方法实现。如果强行给一个抽象属性初始化,编译报错

interface Call{
    var isSuccess:Boolean
        get() = false
        set(value) {
            println("value:$value")
        }
    val isFailure:Boolean = false // 编译报错
}

在子类中用var覆盖一个声明val属性,反之不行。

interface Call{
    var isSuccess:Boolean
        get() = false
        set(value) {
            println("value:$value")
        }
    val isFailure:Boolean
    fun onSuccess(){
        println("onSuccess")
    }
}
class A:Call{
    override var isSuccess: Boolean
        get() = super.isSuccess
        set(value) {}
    override val isFailure: Boolean // 编译不通过val不可以覆盖接口里的var
        set(value) {}
}

接口的继承

接口可以从其他接口派生,派生接口子类中可以选择的覆盖方法或属性

interface Call{
    val name:String
}
interface Call2:Call{
    override val name: String
        get() = "Call2"
}
class A:Call2{}

派生接口没有实现父类接口定义的属性或方法,派生接口子类需要实现,否则编译器报错

interface Call{
    val name:String
}
interface Call2:Call{
}
class A:Call2{} // 需要实现接口属性,报异常
interface Call{
    val name:String
}
interface Call2:Call{
}
class A:Call2{ // 实现了接口属性,编译通过
    override val name: String
        get() = "A"
} 

多个接口中有重名方法

和多个父类类似,使用<>限制super语句区分调用哪个父类同名方法。

interface Call1{
    fun f(){
        println("f")
    }
    fun b()
}
interface Call2{
    fun f(){
        println("f2")
    }
    fun b(){
        println("b2")
    }
}
class A:Call1{
    override fun b() {
        println("a.b")
    }
}
class B:Call1,Call2{
    override fun f() {
        super<Call1>.f()
        super<Call2>.f()
    }

    override fun b() {
        super<Call2>.b()
    }
}

函数式接口

只有一个抽象方法的接口称函数式接口或SAM(单一抽象方法)接口。函数式接口可以有多个非抽象成员,只能由一个抽象成员。Kotlin中定义一个函数类型相当于Java中定义了一个接口。定义一个可空类型block

val block:(()->Unit)?=null

AndroidStudio中Tools->Kotlin->Show Kotlin Bytecode点击Decompile 反编译java代码,函数类型参数block被替换成了Function0

public interface Function0<out R> : Function<R> {
    public operator fun invoke(): R
}
public interface Function1<in P1, out R> : Function<R> {
    public operator fun invoke(p1: P1): R
}
public interface Function2<in P1, in P2, out R> : Function<R> {
    public operator fun invoke(p1: P1, p2: P2): R
}
...

定义的每个函数类型在Java中都有对应的Function接口与对应。Kotlin中函数类型出现替代了Java中接口回到的能力

public interface OnClickListener{
    void onClick(View v);
}
view.setOnClick(new View.OnClickListener(){
    @Override
    public void onClick(View v){}
});

转化为函数类型

(View)->Unit
// 对等的用Lambda完成函数类型的初始化
{view:View->}
// Lambda的View点击事件
view.setOnClickListener({view:View -> println(v)})
// Lambda方法唯一参数,可省略()
view.setOnClickListener{view:View -> println(v)}
// 函数只有一个参数,Lambda省略参数的声明和->.隐式声明it
view.setOnClickListener{println(it)}

总结

接口中方法默认实现 属性定义 接口继承 多个父类同名方法调用 函数式接口等开发中常用到的。