構造方法總結二

構造器間的調用規則

指定構造器必須調用其直接父類的"指定構造器"

便利構造器必須調用同類中的其它構造器(指定或便利)

便利構造器必須最終以調用一個指定構造器結束(無論調用的時指定還是便利, 最終肯定會調用一個指定構造器)

指定構造器總是向上代理(父類)

便利構造器總是橫向代理(當前類)

指定構造與便利構造方法


class Person{
    
    var name : String
    var age : Int
    
    /*
     指定構造方法都是以init開頭的
     */
    init(name:String,age:Int) {
        
        self.name = name
        self.age = age
    }
    
    /*
     被convenience關鍵字修飾的構造方法稱之為便利構造器, 通過調用其它構造方法來初始化
     反而言之, 便利構造器中一定是調用其它構造方法初始化的, 一定要出現self.init
    */
    convenience init() {
        
        self.init(name: "zx", age: 30)
    }
    
    /* 
     類可以擁有多個構造方法
     不能在指定構造方法中調用便利構造方法
     也就是說指定構造方法中不能出現self.init
     */
    init(name:String) {
        
        self.name = name
        self.age = 0
    }
    
   
    convenience init(age:Int) {
        
        //可以在便利構造器中調用指定構造器
//        self.init(name:"lnj", age:30)
        
        // 可以在便利構造器中調用便利構造器
        self.init()
    }
    
    /*
     便利構造器不能和指定構造器同名
    convenience init(name:String) {
        
    }
    */
}

派生類的構造方法


class Man{
    var name : String
    //指定構造方法
    init(name:String) {
        self.name = name
    }
    
    //便利構造方法
    convenience init() {
        self.init(name: "zx")
    }
}


/*
 注意:
 1.默認情況下構造方法不會被繼承
 2.基類的存儲屬性只能通過基類的構造方法初始化
 3.初始化存儲屬性時必須先初始化當前類再初始化父類
 4.不能通過便利構造方法初始化父類, 只能通過調用指定構造方法初始化父類
 */
class SuperMan:Man{
    var age : Int
    // 指定構造器
    init(age:Int) {
        self.age = age
        super.init(name:"lnj")
        //        super.init()
    }
}

構造器間的調用規則使用


class Man2 {
    var name:String
    // 指定構造方法
    init(name:String){
        self.name = name
    }
    // 便利構造方法
    convenience init(){
        self.init(name:"zx")
    }
}


class SuperMan2: Man2 {
    var age: Int
    // 指定構造器
    init(age:Int){
        self.age = age
        super.init(name: "zx")
    }
    convenience init(){
        self.init(age:30)
    }
    convenience init(name:String, age:Int){
        // 調用子類構造器一定能夠初始化所有屬性
//        self.init(age:30)
        // 便利構造器中只能通過self.init來初始化, 不能使用super.init,因為調用父類構造器不一定能完全初始化所有屬性(子類特有)
//        super.init(name: "lnj")
        self.init()
    }
}



兩段式構造

構造過程可以劃分為兩個階段:

  1. 確保當前類和父類所有存儲屬性都被初始化
  2. 做一些其他初始化操作

好處:

  • 可以防止屬性在被初始化之前訪問
  • 可以防止屬性被另外一個構造器意外賦值
  • 注意:構造器的初始化永遠是在所有類的第一階段初始化完畢之后才會開始第二階段

編譯器安全檢查:

  1. 必須先初始化子類特有屬性,在向上代理父類指定構造方法初始化父類屬性
  2. 只能在調用完父類指定構造器后才能訪問父類屬性
  3. 在遍歷構造器中,必須先調用同類其它構造方法后才能訪問屬性
  4. 第一階段完成前不能訪問父類屬性/也不能引用self和調用任何實例方法
class Man3 {
    var name:String
    // 指定構造方法
    init(name:String){
        self.name = name
    }
    // 便利構造方法
    convenience init(){
        self.init(name:"zx")
    }
}


class SuperMan3:Man3{
    var age:Int
    init(age:Int) {
        
        print("SuperMan第一階段開始")
        self.age = age
        //代碼會報錯,因為調用self.name之前還沒有對父類的name進行初始化
        //即便在這個地方修改, 也會被后面的初始化語句覆蓋
//        if age > 30 {
//            self.name = "zs"
//        }
        super.init(name: "lnj")
        
        print("SuperMan第二階段開始")

        if age > 30 {
            self.name = "zs"
        }
    }
    
}


class MonkeyMan:SuperMan3{
    var height:Double
    init(height:Double){
        print("MonkeyMan第一階段開始")
        // 對子類引入的屬性初始化
        self.height = 99.0
        // 對父類引入的屬性進行初始化
        super.init(age: 30)
        
        print("MonkeyMan第二階段開始")
        if height < 100.0{
            self.age = 50
        }
    }
}
var m = MonkeyMan(height: 20)
m.name



重寫指定構造方法: 子類的構造方法和父類的一模一樣



class Man4{
    
    var name : String
    
    //指定構造方法
    init(name:String) {
        self.name = name
    }
    
}

class SuperMan4:Man4{

    var age:Int
    init() {
        self.age = 30
        super.init(name: "lnj")
    }
    
    //如果子類中的構造器和父類一模一樣, 必須加上override關鍵字, 表示重寫父類方法
//    override init(name: String) {
//        self.age = 30
//        super.init(name: name)
//    }
    
    // 將父類的指定構造器重寫成一個便利構造器, 也必須加上override關鍵字, 表示重寫父類方法
    convenience override init(name: String) {
        self.init(name: name)
        self.age = 30
    }
}


便利構造方法不存在重寫



class Man5{
    var name : String
    init(name:String) {
        self.name = name
    }
    
    convenience init() {
        self.init(name: "lnj")
    }
}

class SuperMan5:Man5{
    var age:Int
    init(age:Int) {
        self.age = age
        super.init(name: "lnj")
    }
    
    /*
     Swift中便利構造方法不存在重寫, 如果加上override關鍵字, 系統會去查找父類中有沒有和便利構造方法一樣的指定構造方法, 有就不報錯, 沒有就報錯。
     為什么便利構造器不能重寫呢? 因為便利構造器只能橫向代理, 只能調用當前類的其它構造方法或指定方法, 不可能調用super. 所以不存在重寫。
     也就是說子類的便利構造方法不能直接訪問父類的便利構造方法, 所以不存在重寫的概念

     */
    convenience init(){
        self.init(age:30)
    }
    
}

var sm = SuperMan5()


構造方法的自動繼承

如果子類中沒有定義任何構造器, 且子類中所有的存儲屬性都有缺省值, 會繼承父類中所有的構造方法(包括便利構造器)

如果子類中只是重寫了父類中的某些指定構造器, 不管子類中的存儲屬性是否有缺省值, 都不會繼承父類中的其它構造方法

如果子類重寫了父類中所有的指定構造器, 不管子類中的存儲屬性是否有缺省值, 都會同時繼承父類中的所有便利方法

class Person6 {
    var name:String
    var age:Int
    init(name:String, age:Int){
        self.name = name
        self.age = age
    }
    init(name:String){
        self.name = name
        self.age = 0
    }
    convenience init(){
        self.init(name:"lnj")
    }
}
class SuperMan6: Person6 {
//    var height:Double = 175.0
    var height:Double
    
    init(height:Double){
        self.height = height
        super.init(name: "lnj", age: 30)
    }
    
    override init(name:String, age:Int){
       self.height = 175.0
       super.init(name: name, age: age)
    }
    override init(name:String){
        self.height = 175.0
        super.init(name: name)
    }
}


// 如果子類中沒有定義任何構造器, 且子類中所有的存儲屬性都有缺省值, 會繼承父類中所有的構造方法(包括便利構造器)
// 父類的存儲屬性是由父類的構造器初始化, 子類的存儲屬性是由缺省值初始化的
//var sm = SuperMan(name: "lnj", age: 30)
//var sm = SuperMan(name: "zs")
//var sm = SuperMan()
//print(sm.height)

// 如果子類中只是重寫了父類中的某些指定構造器, 不管子類中的存儲屬性是否有缺省值, 都不會繼承父類中的其它構造方法
//var sm = SuperMan(height: 188.0)

// 如果子類重寫了父類中所有的指定構造器, 不管子類中的存儲屬性是否有缺省值, 都會同時繼承父類中的所有便利方法
var sm6 = SuperMan6()


必須構造器

只要在構造方法的前面加上一個required關鍵字, 那么所有的子類(后續子類)只要定義了構造方法都必須實現該構造方法


class Person7 {
    var name:String
    // 早期Swift版本中沒有這個語法
    required init(name:String){
        self.name = name
    }
}
class SuperMan7: Person7 {
    var age:Int = 30
    // 如果子類沒有定義構造器, 可以不用重寫
    init(){
        self.age = 30
        super.init(name: "lnj")
    }
    // 1.如果子類自定義了構造器, 就必須重寫"必須構造器"
    // 因為如果子類沒有自定義任何構造器, 默認會繼承父類構造器, 所以不用重寫
    // 2.重寫必須構造器不用加override關鍵字, 因為系統看到required關鍵字就會自動查看父類
    // 為什么重寫了還需要加上required關鍵字, 因為所有后續子類都必須重寫
    required init(name: String) {
        self.age = 30
        super.init(name:name)
    }
}
var sm7 = SuperMan7(name: "lnj")

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容