7.3 抽象类
7.3.1 抽象类的定义
含有抽象函数的类(这样的类需要使用abstract修饰符来声明),称为抽象类。
下面是一个抽象类的例子:
abstract class Person(var name: String, var age: Int) : Any() {
abstract var addr: String
abstract val weight: Float
abstract fun doEat()
abstract fun doWalk()
fun doSwim() {
println("I am Swimming ... ")
}
open fun doSleep() {
println("I am Sleeping ... ")
}
}
7.3.2 抽象函数
在上面的这个抽象类中,不仅可以有抽象函数abstract fun doEat()
abstract fun doWalk()
,同时可以有具体实现的函数fun doSwim()
, 这个函数默认是final的。也就是说,我们不能重写这个doSwim函数:
如果一个函数想要设计成能被重写,例如fun doSleep()
,我们给它加上open关键字即可。然后,我们就可以在子类中重写这个open fun doSleep()
:
class Teacher(name: String, age: Int) : Person(name, age) {
override var addr: String = "HangZhou"
override val weight: Float = 100.0f
override fun doEat() {
println("Teacher is Eating ... ")
}
override fun doWalk() {
println("Teacher is Walking ... ")
}
override fun doSleep() {
super.doSleep()
println("Teacher is Sleeping ... ")
}
// override fun doSwim() { // cannot be overriden
// println("Teacher is Swimming ... ")
// }
}
抽象函数是一种特殊的函数:它只有声明,而没有具体的实现。抽象函数的声明格式为:
abstract fun doEat()
关于抽象函数的特征,我们简单总结如下:
- 抽象函数必须用abstract关键字进行修饰
- 抽象函数不用手动添加open,默认被open修饰
- 抽象函数没有具体的实现
- 含有抽象函数的类成为抽象类,必须由abtract关键字修饰。抽象类中可以有具体实现的函数,这样的函数默认是final(不能被覆盖重写),如果想要重写这个函数,给这个函数加上open关键字。
7.3.3 抽象属性
抽象属性就是在var或val前被abstract修饰,抽象属性的声明格式为:
abstract var addr : String
abstract val weight : Float
关于抽象属性,需要注意的是:
- 抽象属相在抽象类中不能被初始化
- 如果在子类中没有主构造函数,要对抽象属性手动初始化。如果子类中有主构造函数,抽象属性可以在主构造函数中声明。
综上所述,抽象类和普通类的区别有:
1.抽象函数必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
也就是说,这三个函数
abstract fun doEat()
abstract fun doWalk()
fun doSwim() {
println("I am Swimming ... ")
}
默认的都是public的。
另外抽象类中的具体实现的函数,默认是final的。上面的三个函数,等价的Java的代码如下:
public abstract void doEat();
public abstract void doWalk();
public final void doSwim() {
String var1 = "I am Swimming ... ";
System.out.println(var1);
}
2.抽象类不能用来创建对象实例。也就是说,下面的写法编译器是不允许的:
3.如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。实现父类抽象函数,我们使用override关键字来表明是重写函数:
class Programmer(override var addr: String, override val weight: Float, name: String, age: Int) : Person(name, age) {
override fun doEat() {
println("Programmer is Eating ... ")
}
override fun doWalk() {
println("Programmer is Walking ... ")
}
}
如果子类没有实现父类的抽象函数,则必须将子类也定义为为abstract类。例如:
abstract class Writer(override var addr: String, override val weight: Float, name: String, age: Int) : Person(name, age) {
override fun doEat() {
println("Programmer is Eating ... ")
}
abstract override fun doWalk();
}
doWalk函数没有实现父类的抽象函数,那么我们在子类中把它依然定义为抽象函数。相应地这个子类,也成为了抽象子类,需要使用abstract关键字来声明。
如果抽象类中含有抽象属性,在实现子类中必须将抽象属性初始化,除非子类也为抽象类。例如我们声明一个Teacher类继承Person类:
class Teacher(name: String, age: Int) : Person(name, age) {
override var addr: String // error, 需要初始化,或者声明为abstract
override val weight: Float // error, 需要初始化,或者声明为abstract
...
}
这样写,编译器会直接报错:
解决方法是,在实现的子类中,我们将抽象属性初始化即可:
class Teacher(name: String, age: Int) : Person(name, age) {
override var addr: String = "HangZhou"
override val weight: Float = 100.0f
override fun doEat() {
println("Teacher is Eating ... ")
}
override fun doWalk() {
println("Teacher is Walking ... ")
}
}