創(chuàng)建自己的類
類與結(jié)構(gòu)相似见转,因?yàn)樗鼈兪鼓梢允褂脤傩院头椒▌?chuàng)建新類型,但是它們有五個(gè)重要的區(qū)別唱遭,我將一次向您介紹所有這些區(qū)別浙垫。
類和結(jié)構(gòu)之間的第一個(gè)區(qū)別是類永遠(yuǎn)不會(huì)帶有成員初始化器。這意味著梧油,如果您的類中有屬性监憎,則必須始終創(chuàng)建自己的初始化程序。
例如:
class Dog {
var name: String
var breed: String
init(name: String, breed: String) {
self.name = name
self.breed = breed
}
}
創(chuàng)建該類的實(shí)例看起來就像是一個(gè)結(jié)構(gòu)一樣:
let poppy = Dog(name: "Poppy", breed: "Poodle")
類繼承
類和結(jié)構(gòu)之間的第二個(gè)區(qū)別是婶溯,您可以基于現(xiàn)有類創(chuàng)建一個(gè)類-它繼承了原始類的所有屬性和方法鲸阔,并且可以在頂部添加自己的類。
這稱為類繼承或子類迄委,您從其繼承的類稱為“父”或“超級(jí)”類褐筛,新類稱為“子”類。
這是Dog
我們剛剛創(chuàng)建的類:
class Dog {
var name: String
var breed: String
init(name: String, breed: String) {
self.name = name
self.breed = breed
}
}
我們可以基于一個(gè)名為的類創(chuàng)建一個(gè)新類Poodle
叙身。默認(rèn)情況下渔扎,它將繼承Dog
相同的屬性和初始化程序:
class Poodle: Dog {
}
但是,我們也可以提供Poodle
自己的初始化程序信轿。我們知道它將始終具有品種“貴賓犬”晃痴,所以我們可以做一個(gè)新的初始化器残吩,只需要一個(gè)name
屬性。更好的是倘核,我們可以讓Poodle初始值設(shè)定項(xiàng)直接調(diào)用Dog初始值設(shè)定項(xiàng)泣侮,以便發(fā)生所有相同的設(shè)置::
class Poodle: Dog {
init(name: String) {
super.init(name: name, breed: "Poodle")
}
}
出于安全原因,Swift總是讓您super.init()
從子類中進(jìn)行調(diào)用-以防萬一父類在創(chuàng)建時(shí)會(huì)做一些重要的工作紧唱。
覆蓋方法
子類可以用其自己的實(shí)現(xiàn)替換父方法-這個(gè)過程稱為Overriding活尊。這是一個(gè)Dog
帶有makeNoise()
方法的普通類:
class Dog {
func makeNoise() {
print("Woof!")
}
}
如果我們創(chuàng)建一個(gè)Poodle
繼承自Dog
的新類,它將繼承該makeNoise()
方法漏益。因此蛹锰,這將顯示“ Woof!”:
class Poodle: Dog {
}
let poppy = Poodle()
poppy.makeNoise()
方法重寫允許我們更改 Poodle
類的makeNoise()
實(shí)現(xiàn)绰疤。
Swift要求我們?cè)谥剌d方法時(shí)使用override func
而不是僅僅使用func
–它阻止您無意中重載方法铜犬,并且如果您嘗試重載父類中不存在的內(nèi)容,則會(huì)收到錯(cuò)誤消息:
class Poodle: Dog {
override func makeNoise() {
print("Yip!")
}
}
進(jìn)行此更改后轻庆,poppy.makeNoise()
將打印“ Yip癣猾!”而不是“ Woof!”榨了。
Final類
盡管類繼承非常有用-實(shí)際上蘋果平臺(tái)的大部分都需要您使用它-有時(shí)您還是想禁止其他開發(fā)人員根據(jù)您自己的類來構(gòu)建他們的類煎谍。
Swift為此提供了一個(gè)關(guān)鍵字final
:當(dāng)您將一個(gè)類聲明為final
時(shí),其他任何類都不能從該類繼承龙屉。這意味著他們無法覆蓋您的方法來更改您的行為–他們需要以編寫類的方式使用您的類呐粘。
要使類最終定名,只需將final
關(guān)鍵字放在其前面转捕,如下所示:
final class Dog {
var name: String
var breed: String
init(name: String, breed: String) {
self.name = name
self.breed = breed
}
}
復(fù)制對(duì)象
類和結(jié)構(gòu)之間的第三個(gè)區(qū)別是如何復(fù)制它們作岖。復(fù)制結(jié)構(gòu)時(shí),原始結(jié)構(gòu)和復(fù)制結(jié)構(gòu)都是不同的-更改一個(gè)不會(huì)更改另一個(gè)五芝。復(fù)制類時(shí)痘儡,原始副本和復(fù)制副本都指向同一件事,因此更改一個(gè)同時(shí)也會(huì)更改另一個(gè)枢步。
例如沉删,這是一個(gè)簡單的Singer
類,具有一個(gè)name
具有默認(rèn)值的屬性:
class Singer {
var name = "Taylor Swift"
}
如果創(chuàng)建該類的實(shí)例并打印其名稱醉途,則將得到“ Taylor Swift”:
var singer = Singer()
print(singer.name)
現(xiàn)在讓我們從第一個(gè)變量創(chuàng)建第二個(gè)變量并更改其名稱:
var singerCopy = singer
singerCopy.name = "Justin Bieber"
由于該方法的類的工作矾瑰,既singer和singerCopy指向內(nèi)存中的同一個(gè)對(duì)象,所以當(dāng)我們打印歌手的名字隘擎,我們?cè)俅慰吹健癑ustin Bieber”:
print(singer.name)
另一方面殴穴,如果Singer
是一個(gè)結(jié)構(gòu),那么我們將第二次打印“ Taylor Swift”:
struct Singer {
var name = "Taylor Swift"
}
反初始化器
類和結(jié)構(gòu)之間的第四個(gè)區(qū)別是,類可以具有反初始化器 -當(dāng)類的實(shí)例被破壞時(shí)運(yùn)行的代碼采幌。
為了說明這一點(diǎn)劲够,這是一個(gè)Person
帶有name
屬性,簡單的初始化程序和打印消息的printGreeting()
方法的類:
class Person {
var name = "John Doe"
init() {
print("\(name) is alive!")
}
func printGreeting() {
print("Hello, I'm \(name)")
}
}
我們將Person
在循環(huán)中創(chuàng)建該類的一些實(shí)例休傍,因?yàn)槊看窝h(huán)進(jìn)行時(shí)征绎,都會(huì)創(chuàng)建一個(gè)新人員,然后將其銷毀:
for _ in 1...3 {
let person = Person()
person.printGreeting()
}
現(xiàn)在是反初始化器尊残。Person
實(shí)例銷毀時(shí)將調(diào)用此方法:
deinit {
print("\(name) is no more!")
}
可變性
類和結(jié)構(gòu)之間的最終區(qū)別是它們處理常量的方式炒瘸。如果您具有帶有可變屬性的常量結(jié)構(gòu)淤堵,則該屬性不能更改寝衫,因?yàn)榻Y(jié)構(gòu)本身是常量。
但是拐邪,如果您的常量類具有可變屬性慰毅,則可以更改該屬性。因此扎阶,類不需要帶有mutating
更改屬性的方法的關(guān)鍵字汹胃。只有結(jié)構(gòu)才需要。
這種差異意味著即使將類創(chuàng)建為常量东臀,也可以更改類的任何變量屬性–這是完全有效的代碼:
class Singer {
var name = "Taylor Swift"
}
let taylor = Singer()
taylor.name = "Ed Sheeran"
print(taylor.name)
如果要阻止這種情況發(fā)生着饥,則需要使該屬性不變:
class Singer {
let name = "Taylor Swift"
}
總結(jié)
- 1.類和結(jié)構(gòu)相似,它們都可以讓您使用屬性和方法創(chuàng)建自己的類型惰赋。
- 2.一個(gè)類可以從另一個(gè)類繼承宰掉,并獲得父類的所有屬性和方法。談?wù)擃悓哟谓Y(jié)構(gòu)是很常見的–一個(gè)類基于另一個(gè)類赁濒,而另一個(gè)類本身又基于另一個(gè)類轨奄。
- 3.您可以使用
final
關(guān)鍵字標(biāo)記一個(gè)類,這將阻止其他類從該類繼承拒炎。 - 4.通過方法覆蓋挪拟,子類可以使用新的實(shí)現(xiàn)替換其父類中的方法。
- 5.當(dāng)兩個(gè)變量指向同一類實(shí)例時(shí)击你,它們都指向同一塊內(nèi)存–一個(gè)會(huì)改變另一個(gè)玉组。
- 6.類可以具有一個(gè)反初始化器,該反初始化器是在銷毀該類的實(shí)例時(shí)運(yùn)行的代碼丁侄。
- 7類并不像構(gòu)造結(jié)構(gòu)那樣強(qiáng)烈地強(qiáng)制執(zhí)行常量–如果將屬性聲明為變量惯雳,則無論如何創(chuàng)建類實(shí)例,都可以對(duì)其進(jìn)行更改绒障。