7.6 继承
继承是面向对象编程的一个重要的方式,因为通过继承,子类就可以扩展父类的功能。
在Kotlin中,所有的类会默认继承Any这个父类,但Any并不完全等同于java中的Object类,因为它只有equals(),hashCode()和toString()这三个方法。
7.6.1 open类
除了抽象类、接口默认可以被继承(实现)外,我们也可以把一个类声明为open的,这样我们就可以继承这个open类。
当我们想定义一个父类时,需要使用open关键字:
1. open class Base{
2. }
当然,抽象类是默认open的。
然后在子类中使用冒号:进行继承
1. class SubClass : Base(){
2. }
如果父类有构造函数,那么必须在子类的主构造函数中进行继承,没有的话则可以选择主构造函数或二级构造函数
1. //父类
2. open class Base(type:String){
4. }
6. //子类
7. class SubClass(type:String) : Base(type){
9. }
Kotlin中的override重写和java中也有所不同,因为Kotlin提倡所有的操作都是明确的,因此需要将希望被重写的函数设为open:
1. open fun doSomething() {}
然后通过override标记实现重写
1. override fun doSomething() {
2. super.doSomething()
3. }
同样的,抽象函数以及接口中定义的函数默认都是open的。
override重写的函数也是open的,如果希望它不被重写,可以在前面增加final :
1. open class SubClass : Base{
2. constructor(type:String) : super(type){
3. }
5. final override fun doSomething() {
6. super.doSomething()
7. }
8. }
7.6.2 多重继承
有些编程语言支持一个类拥有多个父类,例如C++。 我们将这个特性称之为多重继承(multiple inheritance)。多重继承会有二义性和钻石型继承树(DOD:Diamond Of Death)的复杂性问题。Kotlin跟Java一样,没有采用多继承,任何一个子类仅允许一个父类存在,而在多继承的问题场景下,使用实现多个interface 组合的方式来实现多继承的功能。
代码示例:
1. package com.easy.kotlin
3. abstract class Animal {
4. fun doEat() {
5. println("Animal Eating")
6. }
7. }
9. abstract class Plant {
10. fun doEat() {
11. println("Plant Eating")
12. }
13. }
15. interface Runnable {
16. fun doRun()
17. }
19. interface Flyable {
20. fun doFly()
21. }
23. class Dog : Animal(), Runnable {
24. override fun doRun() {
25. println("Dog Running")
26. }
27. }
29. class Eagle : Animal(), Flyable {
30. override fun doFly() {
31. println("Eagle Flying")
32. }
33. }
35. // 始祖鸟, 能飞也能跑
36. class Archaeopteryx : Animal(), Runnable, Flyable {
37. override fun doRun() {
38. println("Archaeopteryx Running")
39. }
41. override fun doFly() {
42. println("Archaeopteryx Flying")
43. }
45. }
47. fun main(args: Array<String>) {
48. val d = Dog()
49. d.doEat()
50. d.doRun()
52. val e = Eagle()
53. e.doEat()
54. e.doFly()
56. val a = Archaeopteryx()
57. a.doEat()
58. a.doFly()
59. a.doRun()
60. }
上述代码类之间的关系,我们用图示如下:

我们可以看出,Archaeopteryx继承了Animal类,用了父类doEat()函数功能;实现了Runnable接口,拥有了doRun()函数规范;实现了Flyable接口,拥有了doFly()函数规范。
在这里,我们通过实现多个接口,组合完成了的多个功能,而不是设计多个层次的复杂的继承关系。
