Kotlin接口
这一篇我们了解Kotlin
的接口。还记得很早之前看过一篇大神的博客,说接口就是特殊的抽象类,其实我个人也是比较认可这种说法的,尤其是在Kotlin
语言中。
接口声明语法:interface IfaceName {}
。
接口默认是open
的,因此不需要再open
关键字修饰。
interface KotlinIface { }
同样地,在接口中声明的函数,默认也是open
且abstract
的。在Idea编辑器中,如果加上open
或者abstract
,编辑器就会提示多余的修饰符。
接大神博客中的说法,接口就是抽象到类中的所有函数都是抽象的。当然,这还是当年针对Java
的描述,在Java8
之后,接口也是允许有默认的函数实现的。(这种暴露年龄的话,好像不应该说。。。)
在Kotlin
中,接口也是可以有默认的函数实现的。
interface KotlinIface { fun show(msg: String) // No implementation. fun read() fun defaultImpl() { // Default implementation. show("default show.") } }
接口一般仅作为某个对象或者对象群的行为定义的,并不做具体实现。因此,接口必须是有对应的类来做实现的。当然实现也有部分实现和完全实现。
一般地,一个类实现某个接口,就必须实现接口中所有的抽象函数。
class KIfaceImpl : KotlinIface { override fun show(msg: String) { } override fun read() { }
但是如果实现接口的类是抽象的,即抽象类实现的,则可以实现接口部分需要的函数即可。
abstract class AbsKIfaceImpl : KotlinIface { override fun show(msg: String) { } }
如果实现接口的类是抽象类,则可以选择性的实现接口的零个或全部函数。
类继承是只能继承单个父类的,但是接口却可以同时实现多个接口。这弥补了单继承的缺点。
interface KIface { fun write() }
比如我们定义新的接口KIface
,让KIfaceImpl
同时实现两个接口。
class KIfaceImpl : KotlinIface, KIface { override fun show(msg: String) { } override fun read() { } override fun write() { } }
我们学习了接口的定义及接口中函数的定义,既然作为一个特殊的抽象类,接口中也是可以定义属性的,但是接口中的属性只能是抽象的,通俗点就是不能赋值的。同样地,和函数一样,默认是open
修饰的。
interface KIface { val name: String fun write() }
和函数一样,实现接口的类,必须提供属性的实现。而对于属性来说,就是它get
和set
方法的实现。
class KIfaceImpl : KIface { override val name: String get() = "KIface" override fun write() { } }
一个类实现了某个接口,那这个类也就是这个接口的一个实例。
class KIfaceImpl : KIface { override val name: String get() = "KIface impl." override fun write() { println("KIface impl write.") } }
我们实现了KIface
接口并实现了它的属性和函数。我们来运行一下:
fun main() { val kIface: KIface = KIfaceImpl() println("name = ${kIface.name}") kIface.write() }
在main
方法中,我们声明了KIface
的对象,但是实际创建的是KIfaceImpl
对象。
执行之后的输出结果:
关于Kotlin
接口的基本内容就这么多,但是有一个比较特殊的使用场景。比如,我们一个类实现了两个接口,但是两个接口中存在同样的函数声明,那这种情形下,关于函数的实现及调用是什么样子的呢?
interface KIfaceA { fun a() { println("KIfaceA -> fun a().") } fun b() } interface KIfaceB { fun a() { println("KIfaceB -> fun a().") } fun b() { println("KIfaceB -> fun b().") } }
我们在两个接口中同时有a()
函数和函数b()
,并且函数声明一样。
我们使用一个类同时实现这两个接口。
class ClassC : KIfaceA, KIfaceB { override fun a() { } override fun b() { } }
在这里,虽然两个接口中仅有一个未实现的函数,但是在ClassC
中,必须要实现两个函数。
编译器提示,必须重写函数a()
因为它继承自多个接口。
class ClassC : KIfaceA, KIfaceB { override fun a() { } override fun b() { } }
那问题又来了,我们怎么样调用接口中的默认实现的函数呢?
强大的编译器给我们提示,你需要使用像super<Foo>
这样的方式调用。
class ClassC : KIfaceA, KIfaceB { override fun a() { super<KIfaceA>.a() super<KIfaceB>.a() } override fun b() { super.b() } }
仔细的同学会注意到,函数b()
的调用并没有像函数a()
一样,这是因为接口中并不存在两个同样的实现,调用父类的函数时,只能调用已经实现的函数。
下一篇,我们将继续学习一些Kotlin
的特殊类。