前言
由于语法上的差异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)}
总结
接口中方法默认实现 属性定义 接口继承 多个父类同名方法调用 函数式接口等开发中常用到的。