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. }

上述代码类之间的关系,我们用图示如下:

Kotlin极简教程

我们可以看出,Archaeopteryx继承了Animal类,用了父类doEat()函数功能;实现了Runnable接口,拥有了doRun()函数规范;实现了Flyable接口,拥有了doFly()函数规范。

在这里,我们通过实现多个接口,组合完成了的多个功能,而不是设计多个层次的复杂的继承关系。