??在Swift中,繼承只能發(fā)生在類身上,結(jié)構(gòu)體和枚舉是不能夠被繼承的。一個(gè)類可以繼承另一個(gè)類的方法、屬性和下標(biāo)。當(dāng)一個(gè)類繼承自另一個(gè)類時(shí),這個(gè)類就被稱之為子類,而被繼承的類則被稱之為父類(超類)。子類可以重寫父類的方法、屬性和下標(biāo)。
??在Objective-C中,所有的類都繼承自NSObject,而Swift中的類可以沒(méi)有父類。沒(méi)有父類的類被稱之為基類。NSObject就是Objective-C中所有其它類的基類,而Swift中并沒(méi)有這樣的基類。
??通常情況下,一個(gè)類只能繼承自一個(gè)父類,這被稱之為單繼承。但是,有些時(shí)候一個(gè)類可以繼承自多個(gè)類,這種情況被稱之為多重繼承。Swift中的類只能是單繼承,而多重繼承則是通過(guò)協(xié)議來(lái)實(shí)現(xiàn)的。也就說(shuō),Swift中的類只能繼承自一個(gè)父類,但是它可以遵守多個(gè)協(xié)議,從而達(dá)到類似于多重繼承的效果。
??1、構(gòu)造函數(shù)的繼承
??我們?cè)谏弦黄恼?a href="http://www.itdecent.cn/p/8787e4d11b4c" target="_blank">《Swift中的構(gòu)造方法》里講構(gòu)造函數(shù)代理時(shí),提到過(guò)便利構(gòu)造函數(shù)和指定構(gòu)造函數(shù),其實(shí)根據(jù)繼承關(guān)系,類里面的構(gòu)造函數(shù)代理又分為橫向代理和向上代理。所謂的橫向代理,就是指發(fā)生在同一個(gè)類中的構(gòu)造函數(shù)代理,也就是我們?cè)谇懊嫠f(shuō)的便利構(gòu)造函數(shù);而向上代理是指子類在構(gòu)造過(guò)程中,要先調(diào)用父類的構(gòu)造函數(shù)來(lái)初始化父類的存儲(chǔ)屬性,這也就是我們所說(shuō)的指定構(gòu)造函數(shù)。
??下面我們來(lái)看一個(gè)具體的示例,在父類Person中,我們通過(guò)調(diào)用它自己的構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)便利構(gòu)造函數(shù),然后在子類Student中調(diào)用指定構(gòu)造函數(shù)來(lái)完成父類存儲(chǔ)屬性的初始化:
// 類的構(gòu)造函數(shù)
class Person {
var age: Int
var name: String
// 父類構(gòu)造函數(shù)1:在構(gòu)造函數(shù)中初始化存儲(chǔ)屬性
init(age: Int, name: String) {
self.age = age
self.name = name
}
// 父類構(gòu)造函數(shù)2:調(diào)用自己的構(gòu)造函數(shù)(便利構(gòu)造函數(shù))
convenience init(A age: Int, N name: String) {
self.init(age: age, name: name)
}
}
class Student: Person {
var no: Int
var height: Double
// 子類構(gòu)造函數(shù)1:子類自己的構(gòu)造函數(shù)
init(age: Int, name: String, no: Int, height: Double) {
// 先初始化自己的存儲(chǔ)屬性
self.no = no
self.height = height
// 再向上調(diào)用父類的構(gòu)造函數(shù)1, 對(duì)父類的存儲(chǔ)屬性進(jìn)行初始化(指定構(gòu)造函數(shù))
super.init(age: age, name: name)
}
// 子類構(gòu)造函數(shù)2:重寫父類的構(gòu)造函數(shù)
convenience override init(age: Int, name: String) {
// 調(diào)用自己的構(gòu)造函數(shù)1來(lái)完成初始化工作(便利構(gòu)造函數(shù))
self.init(age: age, name: name, no: 0, height: 0.0)
}
}
let p = Person(age: 20, name: "Paul") // p.age = 20, p.name = Paul
print("p.age = \(p.age), p.name = \(p.name)")
let stu = Student(age: 22, name: "James", no: 1701, height: 1.72)
// stu.age = 22, stu.name = James, stu.no = 1701, stu.height = 1.72
print("stu.age = \(stu.age), stu.name = \(stu.name), stu.no = \(stu.no), stu.height = \(stu.height)")
??構(gòu)造函數(shù)之間的調(diào)用形成了構(gòu)造函數(shù)鏈,而這個(gè)調(diào)用規(guī)則是有一定限制的。具體應(yīng)遵守的規(guī)則如下:
- 在使用指定構(gòu)造函數(shù)時(shí),必須調(diào)用其直接父類的構(gòu)造函數(shù)。也就是說(shuō),在調(diào)用父類的構(gòu)造函數(shù)初始化父類的存儲(chǔ)屬性時(shí),不能調(diào)用父類的父類的構(gòu)造函數(shù),應(yīng)該調(diào)用直接父類的構(gòu)造函數(shù);
- 在使用便利構(gòu)造函數(shù)時(shí),必須調(diào)用同一個(gè)類中定義的其它構(gòu)造函數(shù)。這個(gè)應(yīng)該很好理解,不用做過(guò)多的解釋。
??2、構(gòu)造過(guò)程安全檢查
??在Swift中,類的構(gòu)造過(guò)程包含兩個(gè)階段:首先分配內(nèi)存,初始化子類的存儲(chǔ)屬性,然后沿著構(gòu)造函數(shù)鏈往上,初始化父類的存儲(chǔ)屬性,直到最頂端父類的所有存儲(chǔ)屬性都初始化完畢;接著,從構(gòu)造函數(shù)鏈最頂端往下,對(duì)每一個(gè)類的存儲(chǔ)屬性進(jìn)行修改、調(diào)用實(shí)例方法,直到所有的類都處理完畢。Swift的編譯器在構(gòu)造過(guò)程中會(huì)進(jìn)行一些安全檢查,它可以有效的防止存儲(chǔ)屬性在初始化之前被訪問(wèn),還可以防止存儲(chǔ)屬性被另外一個(gè)構(gòu)造函數(shù)賦予不同的值。Swift提供了4中安全檢查機(jī)制,接下來(lái)我將做一一說(shuō)明和演示。
??(1)、指定構(gòu)造函數(shù)必須保證其所在類中所有的存儲(chǔ)屬性都完成初始化之后,才能向上調(diào)用父類的構(gòu)造函數(shù)。也就是說(shuō),如果你先調(diào)用父類的構(gòu)造函數(shù),然后再初始化當(dāng)前類中的存儲(chǔ)屬性,編譯器會(huì)報(bào)錯(cuò):
class Student: Person {
var no: Int
var height: Double
init(age: Int, name: String, no: Int, height: Double) {
// 沒(méi)有先初始化自己的存儲(chǔ)屬性,然后再調(diào)用指定構(gòu)造函數(shù),編譯器會(huì)報(bào)錯(cuò)
super.init(age: age, name: name)
// 初始化自己的存儲(chǔ)屬性
self.no = no
self.height = height
}
convenience override init(age: Int, name: String) {
self.init(age: age, name: name, no: 0, height: 0.0)
}
}
??(2)、指定構(gòu)造函數(shù)必須先向上調(diào)用父類的構(gòu)造函數(shù),然后再為繼承的屬性設(shè)置新的值,否則指定構(gòu)造函數(shù)賦予的新值將會(huì)被父類構(gòu)造函數(shù)賦予的值給覆蓋。也就是說(shuō),如果你希望給繼承的屬性賦一個(gè)新值,應(yīng)該將賦值語(yǔ)句放在指定構(gòu)造函數(shù)后面,否則賦予的新值將會(huì)被指定構(gòu)造函數(shù)所覆蓋,從而造成賦新值失?。?/p>
class Student: Person {
var no: Int
var height: Double
init(age: Int, name: String, no: Int, height: Double) {
self.no = no
self.height = height
// 在調(diào)用指定構(gòu)造函數(shù)之前給繼承的屬性age賦新值,這個(gè)會(huì)失敗
self.age = 35
// 向上調(diào)用父類的構(gòu)造函數(shù), 對(duì)父類的存儲(chǔ)屬性進(jìn)行初始化(指定構(gòu)造函數(shù))
super.init(age: age, name: name)
// 先調(diào)用指定構(gòu)造函數(shù),然后再為繼承的屬性賦新值,這個(gè)可以成功
self.name = "Wade"
}
convenience override init(age: Int, name: String) {
self.init(age: age, name: name, no: 0, height: 0.0)
}
}
??(3)、便利構(gòu)造函數(shù)必須先調(diào)用自己所在類中的其它構(gòu)造函數(shù),然后才能給任意屬性(包括從父類繼承的屬性)賦予新值,否則便利構(gòu)造函數(shù)賦予的新值將會(huì)被同一類中的其它構(gòu)造函數(shù)所覆蓋。也就是說(shuō),如果你想在便利構(gòu)造函數(shù)中給屬性賦新值,則應(yīng)該先調(diào)用其它構(gòu)造函數(shù),然后再為屬性賦新值,否則新值將會(huì)被其它構(gòu)造函數(shù)所覆蓋;
class Student: Person {
var no: Int
var height: Double
init(age: Int, name: String, no: Int, height: Double) {
self.no = no
self.height = height
super.init(age: age, name: name)
}
convenience override init(age: Int, name: String) {
// 在便利構(gòu)造函數(shù)中,先給自己的屬性賦新值,然后再調(diào)用其它構(gòu)造函數(shù)
self.height = 2.999999999 // 這個(gè)會(huì)失敗
// 調(diào)用自己的構(gòu)造函數(shù)完成初始化工作(便利構(gòu)造函數(shù))
self.init(age: age, name: name, no: 0, height: 0.0)
// 在便利構(gòu)造函數(shù)中,先調(diào)用所在類中的其它構(gòu)造函數(shù),然后再給自己的屬性賦值
self.no = 188888888 // 這個(gè)可以成功
}
}
??(4)、構(gòu)造函數(shù)在第一階段完成之前,不能調(diào)用實(shí)例方法,也不能讀取實(shí)例屬性。也就是說(shuō),必須保證子類和父類的所有存儲(chǔ)屬性都被初始化完成之后,才能調(diào)用實(shí)例方法,訪問(wèn)實(shí)例的屬性。
class Student: Person {
var no: Int
var height: Double
init(age: Int, name: String, no: Int, height: Double) {
self.no = no
self.height = height
// 指定構(gòu)造方法還沒(méi)有執(zhí)行,父類的屬性還沒(méi)有初始化,這里不能訪問(wèn)父類的屬性
self.getName(name: name)
// 向上調(diào)用父類的構(gòu)造函數(shù), 對(duì)父類的存儲(chǔ)屬性進(jìn)行初始化(指定構(gòu)造函數(shù))
super.init(age: age, name: name)
// 指定構(gòu)造方法執(zhí)行完之后,父類的name屬性已經(jīng)被初始化了,這里可以調(diào)用
self.getName(name: name)
}
convenience override init(age: Int, name: String) {
self.init(age: age, name: name, no: 0, height: 0.0)
}
// 實(shí)例方法
func getName(name: String) {
print("name = \(name)")
}
}
??3、構(gòu)造函數(shù)的繼承
??在Swift中,子類的構(gòu)造函數(shù)有兩種來(lái)源,首先是自己擁有的構(gòu)造函數(shù),其次是從父類中繼承過(guò)來(lái)的構(gòu)造函數(shù)。但是,比不是所有父類構(gòu)造函數(shù)都能夠被子類繼承。子類繼承父類的構(gòu)造函數(shù)是有條件的:
- 如果子類中沒(méi)有任何構(gòu)造函數(shù),那么它將自動(dòng)繼承父類中所有的指定構(gòu)造函數(shù);
- 如果子類中實(shí)現(xiàn)了父類所有的指定構(gòu)造函數(shù),那么它都將自動(dòng)繼承父類所有的便利構(gòu)造函數(shù)。
??4、關(guān)鍵字final
??在定義一個(gè)類時(shí),可以使用關(guān)鍵字final聲明類、屬性、方法和下標(biāo)。被final關(guān)鍵字修飾的類不能夠被繼承,被final關(guān)鍵字修飾的屬性、方法和下標(biāo)不能夠被子類重寫。