《Kotlin核心编程》 ——3.3.2 接口实现多继承
3.3.2 接口实现多继承
一个类实现多个接口相信你肯定不会陌生,这是Java经常干的事情。Kotlin中的接口与Java很相似,但它除了可以定义带默认实现的方法之外,还可以声明抽象的属性。我们的第1个方案,就来看看如何用Kotlin中的接口来实现多继承。
interface Flyer {
fun fly()
fun kind() = "flying animals"
}
interface Animal {
val name: String
fun eat()
fun kind() = "flying animals"
}
class Bird(override val name: String) : Flyer, Animal {
override fun eat() {
println("I can eat")
}
override fun fly() {
println("I can fly")
}
override fun kind() = super<Flyer>.kind()
}
fun main(args: Array<String>) {
val bird = Bird("sparrow")
println(bird.kind())
}
// 运行结果
flying animals
如你所见,Bird类同时实现了Flyer和Animal两个接口,但由于它们都拥有默认的kind方法,同样会引起上面所说的钻石问题。而Kotlin提供了对应的方式来解决这个问题,那就是super关键字,我们可以利用它来指定继承哪个父接口的方法,比如上面代码中的super<Flyer>.kind()。当然我们也可以主动实现方法,覆盖父接口的方法。如:
override fun kind() = "a flying ${this.name}"
那么最终的执行结果就是:
a flying sparrow
通过这个例子,我们再来分析下实现接口的相关语法:
1)在Kotlin中实现一个接口时,需要实现接口中没有默认实现的方法及未初始化的属性,若同时实现多个接口,而接口间又有相同方法名的默认实现时,则需要主动指定使用哪个接口的方法或者重写方法;
2)如果是默认的接口方法,你可以在实现类中通过“super<T>”这种方式调用它,其中T为拥有该方法的接口名;
3)在实现接口的属性和方法时,都必须带上override关键字,不能省略。
除此之外,你应该还注意到了,我们通过主构造方法参数的方式来实现Animal接口中的name属性。我们之前说过,通过val声明的构造方法参数,其实是在类内部定义了一个同名的属性,所以我们当然还可以把name的定义放在Bird类内部。
class Bird(name: String) : Flyer, Animal {
override val name: String // override不要忘记
init {
this.name = name
}
}
name的赋值方式其实无关紧要。比如我们还可以用一个getter对它进行赋值。
class Bird(chineseName: String) : Flyer, Animal {
override val name: String
get() = translate2EnglishName(chineseName)
}
getter和setter
对于getter和setter相信很多Java程序员再熟悉不过了,在Java中通过这种方式来对一个类的私有字段进行取值和赋值的操作,通常用IDE来帮我们自动生成这些方法。但是在很多时候你会发现这种语法真是不堪入目。而Kotlin类不存在字段,只有属性,它同样需要为每个属性生成getter和setter方法。但Kotlin的原则是简洁明了的,既然都要做,那么为何我不幕后就帮你做好了呢?所以你在声明一个类的属性时,要知道背后Kotlin编译器也帮你生成了getter和setter方法。当然你也可以主动声明这两个方法来实现一些特殊的逻辑。还有以下两点需要注意:
1)用val声明的属性将只有getter方法,因为它不可修改;而用var修饰的属性将同时拥有getter和setter方法。
2)用private修饰的属性编译器将会省略getter和setter方法,因为在类外部已经无法访问它了,这两个方法的存在也就没有意义了。
总的来说,用接口模拟实现多继承是我们最常用的方式。但它有时在语义上依旧并不是很明确。下面我们就来看一种更灵活的方式,它能更完整地解决多继承问题。
- 点赞
- 收藏
- 关注作者
评论(0)