《Kotlin从小白到大牛》第12章:继承与多态

第12章 继承与多态

类的继承性是面向对象语言的基本特性,多态性的前提是继承性。Kotlin支持继承性和多态性。本章讨论Kotlin继承性和多态性。

12.1 Kotlin中的继承

为了了解继承性,先看这样一个场景:一位面向对象的程序员小赵,在编程过程中需要描述和处理个人信息,于是定义了类Person,如下所示:
//代码文件:chapter12/src/com/a51work6/section1/Person.kt
package com.a51work6.section1

import java.util.*

class Person {
// 名字
val name: String? = null
// 年龄
val age: Int = 0
// 出生日期
val birthDate: Date? = null

val info: String
    get() = ("Person [name=$name, age=$age, birthDate=$birthDate]")

}
一周以后,小赵又遇到了新的需求,需要描述和处理学生信息,于是他又定义了一个新的类Student,如下所示:
//代码文件:chapter12/src/com/a51work6/section1/Student.kt
package com.a51work6.section1

import java.util.*

class Student {
// 所在学校
val school: String? = null
// 名字
val name: String? = null
// 年龄
val age: Int = 0
// 出生日期
val birthDate: Date? = null

val info: String   
    get() = ("Person [name=$name, age=$age, birthDate=$birthDate]")

}

很多人会认为小赵的做法能够理解并相信这是可行的,但问题在于Student和Person两个类的结构太接近了,后者只比前者多了一个属性school,却要重复定义其他所有的内容,实在让人“不甘心”。Kotlin提供了解决类似问题的机制,那就是类的继承,代码如下所示:
//代码文件:chapter12/src/com/a51work6/section1/Student.kt
package com.a51work6.section1

import java.util.*

class Student : Person() { ①
// 所在学校
val school:String? = null

override val info: String
    get() =("Person [name=$name,age=$age,birthDate=$birthDate]")

}

//代码文件:chapter12/src/com/a51work6/section1/Person.kt
package com.a51work6.section1

import java.util.*

open class Person {//: Any() { ②
// 名字
val name:String? = null
// 年龄
val age: Int =0
// 出生日期
val birthDate:Date? = null

open val info:String
    get() =("Person [name=$name,age=$age,birthDate=$birthDate]")

}
上述代码可见Student类继承了Person类中的成员属性和函数,代码第①行声明Student继承Person,继承使用的冒号(:),冒号前是子类,冒号后是父类。
如果在类的声明中没有使用指明其父类,则默认父类为Any类,kotlin.Any类是Kotlin的根类,所有Kotlin类包括数组都直接或间接继承了Any类,在Any类中定义了一些有关面向对象机制的基本函数,如equals、toString和hashCode等函数。
子类能够继承父类,那么父类需要声明为open,见代码第②行,在Kotlin中默认类不能被继承必须声明为open的。
在这里插入图片描述

12.2 调用父类构造函数

当子类实例化时,不仅需要初始化子类成员属性,也需要初始化父类成员属性,初始化父类成员属性需要调用父类构造函数。
修改12.1节示例,父类Person代码如下:
//代码文件:chapter12/src/com/a51work6/section2/Person.kt
package com.a51work6.section2

import java.util.*

open class Person(val name: String,
val age: Int,
val birthDate: Date)
{ //主构造函数
//次构造函数
constructor(name: String, age: Int) :this(name, age, Date())

override fun toString(): String {
    return("Person [name=$name, age=$age, birthDate=$birthDate]")
}

}
Person类中有两个构造函数,分别是一个主构造函数和一个次构造函数。子类Student继承Person类有多重实现方式,下面分别介绍一下。

12.2.1 使用主构造函数
在子类Student中可以声明主构造函数和次构造函数。示例代码如下:
//代码文件:chapter12/src/com/a51work6/section2/s1/Student.kt
package com.a51work6.section2.s1

import com.a51work6.section2.Person
import java.util.*

class Student(name: String,
age: Int,
birthDate: Date,
val school: String) :Person(name, age, birthDate) { //主构造函数 ①

constructor(name: String, //次构造函数                 
            age: Int,
            school: String) :this(name, age, Date(), school)    //  super(name, age, Date())     ②
            
constructor(name: String, //次构造函数
            school: String) :this(name, 18, school)      //super(name, 18, Date())                ③

}
上述代码第①行是声明Student的主构造函数,主构造函数中val school: String参数,说明会生成属性school,Person(name,
age, birthDate)表达式是调用父类构造函数。代码第②行是声明Student的次构造函数,this(name, age, Date(), school)是调用自己的主构造函数帮助完成初始化,如果将this(name, age, Date(), school)表达式换成super(name, age, Date())则会发生编译错误,super(name, age, Date())是次构造函数中调用父构造函数。代码第③行也是声明Student的次构造函数,this(name, 18, school)是调用自己的代码第②行的次构造函数帮助完成初始化,如果将this(name, 18, school)表达式换成super(name, 18, Date())则会发生编译错误,super(name, 18, Date())是次构造函数中调用父构造函数。
在这里插入图片描述

12.2.2 使用次构造函数重载
在子类Student中可以不声明主构造函数,可以声明多个次构造函数。示例代码如下:
//代码文件:chapter12/src/com/a51work6/section2/s2/Student.kt
package com.a51work6.section2.s2

import com.a51work6.section2.Person
import java.util.*

class Student : Person {

// 所在学校
private var school: String? = null

constructor(name: String,
            age: Int,
            birthDate: Date,
            school: String) :super(name, age, birthDate) {              ①
    this.school = school
}

constructor(name: String,
            age: Int,
            school: String) : this(name,age, Date(), school) {           ②
    this.school = school
}

}
上述代码第①行和第②行都是声明次构造函数,其中代码第①行的次构造函数中super(name, age, birthDate)表达式是调用父构造函数。代码第②行的次构造函数中this(name, age, Date(), school)表达式是调用代码第①行自己的次构造函数。
在这里插入图片描述
12.2.3 使用参数默认值调用构造函数
一个类有多个多个造函数时,多个构造函数之间构成了重载关系,Kotlin从语法角度是支持重载的,但更推荐采用参数默认值方式。
示例代码如下:
//代码文件:chapter12/src/com/a51work6/section2/s3/Student.kt
package com.a51work6.section2.s3

import com.a51work6.section2.Person
import java.util.*

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值