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){
  3. }
  4. //子类
  5. class SubClass(type:String) : Base(type){
  6. }

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. }
  4. final override fun doSomething() {
  5. super.doSomething()
  6. }
  7. }

7.6.2 多重继承

有些编程语言支持一个类拥有多个父类,例如C++。 我们将这个特性称之为多重继承(multiple inheritance)。多重继承会有二义性和钻石型继承树(DOD:Diamond Of Death)的复杂性问题。Kotlin跟Java一样,没有采用多继承,任何一个子类仅允许一个父类存在,而在多继承的问题场景下,使用实现多个interface 组合的方式来实现多继承的功能。

代码示例:

  1. package com.easy.kotlin
  2. abstract class Animal {
  3. fun doEat() {
  4. println("Animal Eating")
  5. }
  6. }
  7. abstract class Plant {
  8. fun doEat() {
  9. println("Plant Eating")
  10. }
  11. }
  12. interface Runnable {
  13. fun doRun()
  14. }
  15. interface Flyable {
  16. fun doFly()
  17. }
  18. class Dog : Animal(), Runnable {
  19. override fun doRun() {
  20. println("Dog Running")
  21. }
  22. }
  23. class Eagle : Animal(), Flyable {
  24. override fun doFly() {
  25. println("Eagle Flying")
  26. }
  27. }
  28. // 始祖鸟, 能飞也能跑
  29. class Archaeopteryx : Animal(), Runnable, Flyable {
  30. override fun doRun() {
  31. println("Archaeopteryx Running")
  32. }
  33. override fun doFly() {
  34. println("Archaeopteryx Flying")
  35. }
  36. }
  37. fun main(args: Array<String>) {
  38. val d = Dog()
  39. d.doEat()
  40. d.doRun()
  41. val e = Eagle()
  42. e.doEat()
  43. e.doFly()
  44. val a = Archaeopteryx()
  45. a.doEat()
  46. a.doFly()
  47. a.doRun()
  48. }

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

Kotlin极简教程

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

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