7.3 抽象类

7.3.1 抽象类的定义

含有抽象函数的类(这样的类需要使用abstract修饰符来声明),称为抽象类。

下面是一个抽象类的例子:

  1. abstract class Person(var name: String, var age: Int) : Any() {
  2. abstract var addr: String
  3. abstract val weight: Float
  4. abstract fun doEat()
  5. abstract fun doWalk()
  6. fun doSwim() {
  7. println("I am Swimming ... ")
  8. }
  9. open fun doSleep() {
  10. println("I am Sleeping ... ")
  11. }
  12. }

7.3.2 抽象函数

在上面的这个抽象类中,不仅可以有抽象函数abstract fun doEat() abstract fun doWalk(),同时可以有具体实现的函数fun doSwim(), 这个函数默认是final的。也就是说,我们不能重写这个doSwim函数:

Kotlin极简教程

如果一个函数想要设计成能被重写,例如fun doSleep(),我们给它加上open关键字即可。然后,我们就可以在子类中重写这个open fun doSleep():

  1. class Teacher(name: String, age: Int) : Person(name, age) {
  2. override var addr: String = "HangZhou"
  3. override val weight: Float = 100.0f
  4. override fun doEat() {
  5. println("Teacher is Eating ... ")
  6. }
  7. override fun doWalk() {
  8. println("Teacher is Walking ... ")
  9. }
  10. override fun doSleep() {
  11. super.doSleep()
  12. println("Teacher is Sleeping ... ")
  13. }
  14. // override fun doSwim() { // cannot be overriden
  15. // println("Teacher is Swimming ... ")
  16. // }
  17. }

抽象函数是一种特殊的函数:它只有声明,而没有具体的实现。抽象函数的声明格式为:

  1. abstract fun doEat()

关于抽象函数的特征,我们简单总结如下:

  • 抽象函数必须用abstract关键字进行修饰
  • 抽象函数不用手动添加open,默认被open修饰
  • 抽象函数没有具体的实现
  • 含有抽象函数的类成为抽象类,必须由abtract关键字修饰。抽象类中可以有具体实现的函数,这样的函数默认是final(不能被覆盖重写),如果想要重写这个函数,给这个函数加上open关键字。

    7.3.3 抽象属性

抽象属性就是在var或val前被abstract修饰,抽象属性的声明格式为:

  1. abstract var addr : String
  2. abstract val weight : Float

关于抽象属性,需要注意的是:

  1. 抽象属相在抽象类中不能被初始化
  2. 如果在子类中没有主构造函数,要对抽象属性手动初始化。如果子类中有主构造函数,抽象属性可以在主构造函数中声明。

综上所述,抽象类和普通类的区别有:

1.抽象函数必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。

也就是说,这三个函数

  1. abstract fun doEat()
  2. abstract fun doWalk()
  3. fun doSwim() {
  4. println("I am Swimming ... ")
  5. }

默认的都是public的。

另外抽象类中的具体实现的函数,默认是final的。上面的三个函数,等价的Java的代码如下:

  1. public abstract void doEat();
  2. public abstract void doWalk();
  3. public final void doSwim() {
  4. String var1 = "I am Swimming ... ";
  5. System.out.println(var1);
  6. }

2.抽象类不能用来创建对象实例。也就是说,下面的写法编译器是不允许的:

Kotlin极简教程

3.如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。实现父类抽象函数,我们使用override关键字来表明是重写函数:

  1. class Programmer(override var addr: String, override val weight: Float, name: String, age: Int) : Person(name, age) {
  2. override fun doEat() {
  3. println("Programmer is Eating ... ")
  4. }
  5. override fun doWalk() {
  6. println("Programmer is Walking ... ")
  7. }
  8. }

如果子类没有实现父类的抽象函数,则必须将子类也定义为为abstract类。例如:

  1. abstract class Writer(override var addr: String, override val weight: Float, name: String, age: Int) : Person(name, age) {
  2. override fun doEat() {
  3. println("Programmer is Eating ... ")
  4. }
  5. abstract override fun doWalk();
  6. }

doWalk函数没有实现父类的抽象函数,那么我们在子类中把它依然定义为抽象函数。相应地这个子类,也成为了抽象子类,需要使用abstract关键字来声明。

如果抽象类中含有抽象属性,在实现子类中必须将抽象属性初始化,除非子类也为抽象类。例如我们声明一个Teacher类继承Person类:

  1. class Teacher(name: String, age: Int) : Person(name, age) {
  2. override var addr: String // error, 需要初始化,或者声明为abstract
  3. override val weight: Float // error, 需要初始化,或者声明为abstract
  4. ...
  5. }

这样写,编译器会直接报错:

Kotlin极简教程

解决方法是,在实现的子类中,我们将抽象属性初始化即可:

  1. class Teacher(name: String, age: Int) : Person(name, age) {
  2. override var addr: String = "HangZhou"
  3. override val weight: Float = 100.0f
  4. override fun doEat() {
  5. println("Teacher is Eating ... ")
  6. }
  7. override fun doWalk() {
  8. println("Teacher is Walking ... ")
  9. }
  10. }