Kotlin繼承
繼承是面向對象編程語言的一個重要特徵。 繼承允許將類(或基類或父類)的特性繼承到新類(或派生類或子類)。
主類稱爲超類(或父類),繼承超類的類稱爲子類(或子類)。 子類包含超類的特性以及它自己的特性。
當兩個或多個類具有相同的屬性時,這就引入繼承的概念。 繼承用於提高代碼可重用性。 派生類只有一個基類,但可以有多個接口,而基類可能有一個或多個派生類。
在Kotlin中,派生類在類頭中使用冒號(:
)操作符來繼承基類(在派生類名或構造函數之後)。如下代碼所示 -
// 聲明一個基類
open class Base(p: Int){
}
// 聲明一個繼承自 Base 類(也稱爲基類)的子類:Derived
class Derived(p: Int) : Base(p){
}
假設有兩個不同的類:Programmer
和Salesman
,它們具有公共屬性name
,age
和salary
以及它們各自的方法:functionalitiesdoProgram()
和fieldWork()
。 繼承的特性允許繼承包含公共特性的(Employee
基類)。
open class Employee(name: String, age: Int, salary: Float) {
// code of employee
}
class Programmer(name: String, age: Int, salary: Float): Employee(name,age,salary) {
// code of programmer
}
class Salesman(name: String, age: Int, salary: Float): Employee(name,age,salary) {
// code of salesman
}
所有Kotlin類都有一個共同的超類Any
,它是沒有明確指定超類時使用的默認超類。
例如,類Example
是隱式繼承Any
類的,即使沒有明確寫上。
class Example
Kotlin open關鍵字
由於Kotlin類默認爲final
,因此不能簡單地繼承它們。在類之前使用open
關鍵字來爲其它類繼承這個類。
示例:
open class Example{
// I can now be extended!
}
Kotlin繼承類中的字段
當繼承一個類來派生類時,所有的字段和函數都是繼承的。 可以在派生類中使用這些字段和函數。
示例:
open class Base{
val x = 10
}
class Derived: Base() {
fun foo() {
println("x is equal to " + x)
}
}
fun main(args: Array<String>) {
val derived = Derived()
derived.foo()
}
執行上面示例代碼,得到以下結果 -
x is equal to 10
Kotlin從類繼承方法
open class Bird {
fun fly() {
println("flying...")
}
}
class Duck: Bird() {
fun swim() {
println("swimming...")
}
}
fun main(args: Array<String>) {
val duck = Duck()
duck.fly()
duck.swim()
}
執行上面示例代碼,得到以下結果 -
flying...
swimming...
Kotlin繼承示例
在這裏,聲明一個類Employee
是超類,Programmer
和Salesman
是它的子類。 子類繼承屬性:name
, age
和 salary
以及包含子類自身的函數,如:doProgram()
和fieldWork()
。
open class Employee(name: String, age: Int, salary: Float) {
init {
println("Name is $name.")
println("Age is $age")
println("Salary is $salary")
}
}
class Programmer(name: String, age: Int, salary: Float):Employee(name,age,salary){
fun doProgram() {
println("programming is my passion.")
}
}
class Salesman(name: String, age: Int, salary: Float):Employee(name,age,salary){
fun fieldWork() {
println("travelling is my hobby.")
}
}
fun main(args: Array<String>){
val obj1 = Programmer("Maxsu", 25, 40000f)
obj1.doProgram()
val obj2 = Salesman("Ajax", 24, 30000f)
obj2.fieldWork()
}
執行上面示例代碼,得到以下結果 -
Name is Maxsu.
Age is 25
Salary is 40000.0
programming is my passion.
Name is Ajax.
Age is 24
Salary is 30000.0
travelling is my hobby.
Kotlin繼承和主要構造函數
如果基類和派生類都具有主構造函數,則參數在基類的主構造函數中初始化。 在上面的繼承示例中,所有類都包含三個參數:name
,age
和salary
,所有這些參數都在基類的主構造函數中初始化。
當基類和派生類在主構造函數中包含不同數量的參數時,基類參數將從派生類對象初始化。
示例代碼
open class Employee(name: String,salary: Float) {
init {
println("姓名:$name.")
println("薪水:$salary")
}
}
class Programmer(name: String, dept: String, salary: Float):Employee(name,salary){
init {
println("$name 所在部門:$dept ,薪水爲:$salary.")
}
fun doProgram() {
println("編程我有激情.")
}
}
class Salesman(name: String, dept: String, salary: Float):Employee(name,salary){
init {
println("$name 所在部門:$dept ,薪水爲:$salary.")
}
fun fieldWork() {
println("我的愛好是:旅遊.")
}
}
fun main(args: Array<String>){
val obj1 = Programmer("Susen", "技術部", 40000f)
obj1.doProgram()
println()
val obj2 = Salesman("Ajax", "市場部", 30000f)
obj2.fieldWork()
}
執行上面示例代碼,得到以下結果 -
姓名:Susen.
薪水:40000.0
Susen 所在部門:技術部 ,薪水爲:40000.0.
編程我有激情.
姓名:Ajax.
薪水:30000.0
Ajax 所在部門:市場部 ,薪水爲:30000.0.
我的愛好是:旅遊.
當創建派生類的對象時,它首先調用超類並執行基類的init
塊,然後執行它自己的init
塊。
Kotlin繼承和輔助構造函數
如果派生類不包含任何主構造函數,則需要使用super
關鍵字從派生類調用基類輔助構造函數。
示例:
open class Patent {
constructor(name: String, id: Int) {
println("執行超類構造函數: $id , $name ")
}
}
class Child: Patent {
constructor(name: String, id: Int, dept: String): super(name, id) {
print("使用屬性執行子類構造函數:$name, $id, $dept")
}
}
fun main(args: Array<String>) {
val child = Child("Maxsu",10010, "技術部")
}
執行上面示例代碼,得到以下結果 -
執行超類構造函數: 10010 , Maxsu
使用屬性執行子類構造函數:Maxsu, 10010, 技術部
在上面的示例中,當創建Child
類的對象時,它調用其構造函數並使用值:「Maxsu」,「10010」和「技術部」初始化其參數。 同時,Child
類構造函數使用具有name
和id
值的super
關鍵字調用超類的構造函數。 由於super
關鍵字的存在,超類構造函數的主體首先執行並返回到Child
類構造函數。
Kotlin方法覆蓋
方法覆蓋意味着將super(parent)
類的方法的特定實現提供到子類(子)類中。
換句話說,當子類重新定義或修改其超類的方法爲子類時,它被稱爲方法覆蓋。 方法覆蓋只能在繼承中實現。
Kotlin方法覆蓋的規則
- 父類及要覆蓋的方法或屬性必須是
open
的(非final
)。 - 基類和派生類的方法名必須相同。
- 方法必須具有與基類相同的參數。
沒有覆蓋的繼承示例
open class Bird {
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
}
class Duck: Bird() {
}
fun main(args: Array<String>) {
val p = Parrot()
p.fly()
val d = Duck()
d.fly()
}
執行上面示例代碼,得到以下結果 -
Bird is flying...
Bird is flying...
在上面的例子中,一個沒有覆蓋基類方法的程序出現派生類Parrot
和Duck
類執行相同的操作。 爲了克服這個問題,使用方法覆蓋這個概念。
Kotlin方法覆蓋的示例
在此示例中,子類Parrot
和Duck
中覆蓋父類Bird
的方法fly()
。 要覆蓋父類的方法,必須將要覆蓋的父類及方法聲明爲open
。 同時,在子類中重寫的方法必須以override
關鍵字開頭。
open class Bird {
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
override fun fly() {
println("Parrot is flying...")
}
}
class Duck: Bird() {
override fun fly() {
println("Duck is flying...")
}
}
fun main(args: Array<String>) {
val p = Parrot()
p.fly()
val d = Duck()
d.fly()
}
執行上面示例代碼,得到以下結果 -
Parrot is flying...
Duck is flying...
Kotlin屬性覆蓋的示例
超類的屬性也可以在子類中覆蓋,這個實現類似於方法。 在子類Parrot
和Duck
中重寫並修改Bird
類的color
屬性。
open class Bird {
open var color = "黑色"
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
override var color = "綠色"
override fun fly() {
println("Parrot is flying...")
}
}
class Duck: Bird() {
override var color = "花色"
override fun fly() {
println("Duck is flying...")
}
}
fun main(args: Array<String>) {
val p = Parrot()
p.fly()
println(p.color)
val d = Duck()
d.fly()
println(d.color)
}
執行上面示例代碼,得到以下結果 -
Parrot is flying...
綠色
Duck is flying...
花色
可以在繼承中使用var
屬性覆蓋val
屬性,但反之亦然。
Kotlin超類實現
派生類也可以使用super
關鍵字調用超類方法和屬性。
例如:
open class Bird {
open var color = "黑色"
open fun fly() {
println("Bird is flying...")
}
}
class Parrot: Bird() {
override var color = "綠色"
override fun fly() {
super.fly()
println("Parrot is flying...")
}
}
fun main(args: Array<String>) {
val p = Parrot()
p.fly()
println(p.color)
}
執行上面示例代碼,得到以下結果 -
Bird is flying...
Parrot is flying...
綠色
Kotlin多類實現
在Kotlin中,派生類在尖括號中使用超類型名稱,即,super <Base>
,當它實現多個類中提供的相同函數名時。
例如,派生類Parrot
擴展超類Bird
並實現相同的Duck接口函數fly()
。 要調用每個類和接口的特定方法,必須在尖括號中提到超類型名稱爲super <Bird>.fly()
和super <Duck>.fly()
。
open class Bird {
open var color = "黑色"
open fun fly() {
println("Bird is flying...")
}
}
interface Duck {
fun fly() {
println("Duck is flying...")
}
}
class Parrot: Bird(),Duck {
override var color = "綠色"
override fun fly() {
super<Bird>.fly()
super<Duck>.fly()
println("Parrot is flying...")
}
}
fun main(args: Array<String>) {
val p = Parrot()
p.fly()
println(p.color)
}
執行上面示例代碼,得到以下結果 -
Bird is flying...
Duck is flying...
Parrot is flying...
綠色