OneDayOneSwift[14] - Initialization

通過定義構(gòu)造器(Initializers)來實現(xiàn)構(gòu)造過程,這些構(gòu)造器可以看做是用來創(chuàng)建特定類型新實例的特殊方法。與 Objective-C 中的構(gòu)造器不同,Swift 的構(gòu)造器無需返回值,它們的主要任務(wù)是保證新實例在第一次使用前完成正確的初始化。

存儲屬性的初始賦值

ps: 當(dāng)你為存儲型屬性設(shè)置默認值或者在構(gòu)造器中為其賦值時,它們的值是被直接設(shè)置的,不會觸發(fā)任何屬性觀察者(property observers)。

默認屬性值

ps: 如果一個屬性總是使用相同的初始值,那么為其設(shè)置一個默認值比每次都在構(gòu)造器中賦值要好。兩種方法的效果是一樣的,只不過使用默認值讓屬性的初始化和聲明結(jié)合得更緊密。使用默認值能讓你的構(gòu)造器更簡潔、更清晰,且能通過默認值自動推導(dǎo)出屬性的類型;同時,它也能讓你充分利用默認構(gòu)造器、構(gòu)造器繼承等特性

參數(shù)的內(nèi)部名稱和外部名稱

然而,構(gòu)造器并不像函數(shù)和方法那樣在括號前有一個可辨別的名字。因此在調(diào)用構(gòu)造器時,主要通過構(gòu)造器中的參數(shù)名和類型來確定應(yīng)該被調(diào)用的構(gòu)造器。正因為參數(shù)如此重要,如果你在定義構(gòu)造器時沒有提供參數(shù)的外部名字,Swift 會為每個構(gòu)造器的參數(shù)自動生成一個跟內(nèi)部名字相同的外部名。

可選屬性類型

如果你定制的類型包含一個邏輯上允許取值為空的存儲型屬性——無論是因為它無法在初始化時賦值,還是因為它在之后某個時間點可以賦值為空——你都需要將它定義為可選類型optional type可選類型的屬性將自動初始化為nil,表示這個屬性是有意在初始化時設(shè)置為空的。

默認構(gòu)造器

如果結(jié)構(gòu)體或類的所有屬性都有默認值,同時沒有自定義的構(gòu)造器,那么 Swift 會給這些結(jié)構(gòu)體或類提供一個默認構(gòu)造器。這個默認構(gòu)造器將簡單地創(chuàng)建一個所有屬性值都設(shè)置為默認值的實例。

結(jié)構(gòu)體的逐一成員構(gòu)造器

除了上面提到的默認構(gòu)造器,如果結(jié)構(gòu)體沒有提供自定義的構(gòu)造器,它們將自動獲得一個逐一成員構(gòu)造器,即使結(jié)構(gòu)體的存儲型屬性沒有默認值。

值類型的構(gòu)造器代理

如果你為某個值類型定義了一個自定義的構(gòu)造器,你將無法訪問到默認構(gòu)造器(如果是結(jié)構(gòu)體,還將無法訪問逐一成員構(gòu)造器)。這個限制可以防止你為值類型定義了一個進行額外必要設(shè)置的復(fù)雜構(gòu)造器之后,別人還是錯誤地使用了一個自動生成的構(gòu)造器。

ps: 假如你希望默認構(gòu)造器、逐一成員構(gòu)造器以及你自己的自定義構(gòu)造器都能用來創(chuàng)建實例,可以將自定義的構(gòu)造器寫到擴展(extension)中,而不是寫在值類型的原始定義中。

下面例子將定義一個結(jié)構(gòu)體Rect,用來代表幾何矩形。這個例子需要兩個輔助的結(jié)構(gòu)體Size和Point,它們各自為其所有的屬性提供了初始值0.0。你可以通過以下三種方式為Rect創(chuàng)建實例——使用被初始化為默認值的origin和size屬性來初始化;提供指定的origin和size實例來初始化;提供指定的center和size來初始化。在下面Rect結(jié)構(gòu)體定義中,我們?yōu)檫@三種方式提供了三個自定義的構(gòu)造器:

struct Rect {
    var origin = Point()
    var size = Size()
    init() {}
    init(origin: Point, size: Size) {
        self.origin = origin
        self.size = size
    }
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}

類的構(gòu)造器代理規(guī)則

為了簡化指定構(gòu)造器和便利構(gòu)造器之間的調(diào)用關(guān)系,Swift 采用以下三條規(guī)則來限制構(gòu)造器之間的代理調(diào)用:

規(guī)則 1

指定構(gòu)造器必須調(diào)用其直接父類的的指定構(gòu)造器。

規(guī)則 2

便利構(gòu)造器必須調(diào)用同一類中定義的其它構(gòu)造器。

規(guī)則 3

便利構(gòu)造器必須最終導(dǎo)致一個指定構(gòu)造器被調(diào)用。

一個更方便記憶的方法是:

  • 指定構(gòu)造器必須總是向上代理
  • 便利構(gòu)造器必須總是橫向代理
initializerDelegation01_2x.png

如圖所示,父類中包含一個指定構(gòu)造器和兩個便利構(gòu)造器。其中一個便利構(gòu)造器調(diào)用了另外一個便利構(gòu)造器,而后者又調(diào)用了唯一的指定構(gòu)造器。這滿足了上面提到的規(guī)則 2 和 3。這個父類沒有自己的父類,所以規(guī)則 1 沒有用到。

子類中包含兩個指定構(gòu)造器和一個便利構(gòu)造器。便利構(gòu)造器必須調(diào)用兩個指定構(gòu)造器中的任意一個,因為它只能調(diào)用同一個類里的其他構(gòu)造器。這滿足了上面提到的規(guī)則 2 和 3。而兩個指定構(gòu)造器必須調(diào)用父類中唯一的指定構(gòu)造器,這滿足了規(guī)則 1。

ps:這些規(guī)則不會影響類的實例如何創(chuàng)建。任何上圖中展示的構(gòu)造器都可以用來創(chuàng)建完全初始化的實例。這些規(guī)則只影響類定義如何實現(xiàn)。

下面圖例中展示了一種涉及四個類的更復(fù)雜的類層級結(jié)構(gòu)。它演示了指定構(gòu)造器是如何在類層級中充當(dāng)“管道”的作用,在類的構(gòu)造器鏈上簡化了類之間的相互關(guān)系。

initializerDelegation02_2x.png

兩段式構(gòu)造過程

Swift 中類的構(gòu)造過程包含兩個階段。第一個階段,每個存儲型屬性通過引入它們的類的構(gòu)造器來設(shè)置初始值。當(dāng)每一個存儲型屬性值被確定后,第二階段開始,它給每個類一次機會在新實例準(zhǔn)備使用之前進一步定制它們的存儲型屬性。

兩段式構(gòu)造過程的使用讓構(gòu)造過程更安全,同時在整個類層級結(jié)構(gòu)中給予了每個類完全的靈活性。兩段式構(gòu)造過程可以防止屬性值在初始化之前被訪問,也可以防止屬性被另外一個構(gòu)造器意外地賦予不同的值。

ps: Swift 的兩段式構(gòu)造過程跟 Objective-C 中的構(gòu)造過程類似。最主要的區(qū)別在于階段 1,Objective-C 給每一個屬性賦值0或空值(比如說0nil)。Swift 的構(gòu)造流程則更加靈活,它允許你設(shè)置定制的初始值,并自如應(yīng)對某些屬性不能以0nil作為合法默認值的情況。

Swift 編譯器將執(zhí)行 4 種有效的安全檢查,以確保兩段式構(gòu)造過程能順利完成:
安全檢查 1

指定構(gòu)造器必須保證它所在類引入的所有屬性都必須先初始化完成,之后才能將其它構(gòu)造任務(wù)向上代理給父類中的構(gòu)造器。

如上所述,一個對象的內(nèi)存只有在其所有存儲型屬性確定之后才能完全初始化。為了滿足這一規(guī)則,指定構(gòu)造器必須保證它所在類引入的屬性在它往上代理之前先完成初始化。

安全檢查 2

指定構(gòu)造器必須先向上代理調(diào)用父類構(gòu)造器,然后再為繼承的屬性設(shè)置新值。如果沒這么做,指定構(gòu)造器賦予的新值將被父類中的構(gòu)造器所覆蓋。

安全檢查 3

便利構(gòu)造器必須先代理調(diào)用同一類中的其它構(gòu)造器,然后再為任意屬性賦新值。如果沒這么做,便利構(gòu)造器賦予的新值將被同一類中其它指定構(gòu)造器所覆蓋。

安全檢查 4

構(gòu)造器在第一階段構(gòu)造完成之前,不能調(diào)用任何實例方法,不能讀取任何實例屬性的值,不能引用self作為一個值。

類實例在第一階段結(jié)束以前并不是完全有效的。只有第一階段完成后,該實例才會成為有效實例,才能訪問屬性和調(diào)用方法。

以下是兩段式構(gòu)造過程中基于上述安全檢查的構(gòu)造流程展示:
階段 1

  • 某個指定構(gòu)造器或便利構(gòu)造器被調(diào)用。
  • 完成新實例內(nèi)存的分配,但此時內(nèi)存還沒有被初始化。
  • 指定構(gòu)造器確保其所在類引入的所有存儲型屬性都已賦初值。存儲型屬性所屬的內(nèi)存完成初始化。
  • 指定構(gòu)造器將調(diào)用父類的構(gòu)造器,完成父類屬性的初始化。
  • 這個調(diào)用父類構(gòu)造器的過程沿著構(gòu)造器鏈一直往上執(zhí)行,直到到達構(gòu)造器鏈的最頂部。
  • 當(dāng)?shù)竭_了構(gòu)造器鏈最頂部,且已確保所有實例包含的存儲型屬性都已經(jīng)賦值,這個實例的內(nèi)存被認為已經(jīng)完全初始化。此時階段 1 完成。

階段 2

  • 從頂部構(gòu)造器鏈一直往下,每個構(gòu)造器鏈中類的指定構(gòu)造器都有機會進一步定制實例。構(gòu)造器此時可以訪問self、修改它的屬性并調(diào)用實例方法等等。
  • 最終,任意構(gòu)造器鏈中的便利構(gòu)造器可以有機會定制實例和使用self。

構(gòu)造器的繼承和重寫

跟 Objective-C 中的子類不同,Swift 中的子類默認情況下不會繼承父類的構(gòu)造器。Swift 的這種機制可以防止一個父類的簡單構(gòu)造器被一個更專業(yè)的子類繼承,并被錯誤地用來創(chuàng)建子類的實例。

ps: 父類的構(gòu)造器僅會在安全和適當(dāng)?shù)那闆r下被繼承。

當(dāng)你在編寫一個和父類中指定構(gòu)造器相匹配的子類構(gòu)造器時,你實際上是在重寫父類的這個指定構(gòu)造器。因此,你必須在定義子類構(gòu)造器時帶上override修飾符。即使你重寫的是系統(tǒng)自動提供的默認構(gòu)造器,也需要帶上override修飾符

ps: 當(dāng)你重寫一個父類的指定構(gòu)造器時,你總是需要寫override修飾符,即使你的子類將父類的指定構(gòu)造器重寫為了便利構(gòu)造器。

相反,如果你編寫了一個和父類便利構(gòu)造器相匹配的子類構(gòu)造器,由于子類不能直接調(diào)用父類的便利構(gòu)造器,因此,嚴(yán)格意義上來講,你的子類并未對一個父類構(gòu)造器提供重寫。最后的結(jié)果就是,你在子類中“重寫”一個父類便利構(gòu)造器時,不需要加override前綴。

構(gòu)造器的自動繼承

如上所述,子類在默認情況下不會繼承父類的構(gòu)造器。但是如果滿足特定條件,父類構(gòu)造器是可以被自動繼承的。在實踐中,這意味著對于許多常見場景你不必重寫父類的構(gòu)造器,并且可以在安全的情況下以最小的代價繼承父類的構(gòu)造器。

假設(shè)你為子類中引入的所有新屬性都提供了默認值,以下 2 個規(guī)則適用:
規(guī)則 1
如果子類沒有定義任何指定構(gòu)造器,它將自動繼承所有父類的指定構(gòu)造器。

規(guī)則 2
如果子類提供了所有父類指定構(gòu)造器的實現(xiàn)——無論是通過規(guī)則 1 繼承過來的,還是提供了自定義實現(xiàn)——它將自動繼承所有父類的便利構(gòu)造器。(即使屬性沒有默認值,只要實現(xiàn)了父類的所有指定構(gòu)造器,就會自動繼承父類的所有便利構(gòu)造器)

即使你在子類中添加了更多的便利構(gòu)造器,這兩條規(guī)則仍然適用。

ps: 對于規(guī)則 2,子類可以將父類的指定構(gòu)造器實現(xiàn)為便利構(gòu)造器。

可失敗構(gòu)造器

如果一個類、結(jié)構(gòu)體或枚舉類型的對象,在構(gòu)造過程中有可能失敗,則為其定義一個可失敗構(gòu)造器。這里所指的“失敗”是指,如給構(gòu)造器傳入無效的參數(shù)值,或缺少某種所需的外部資源,又或是不滿足某種必要的條件等。

ps: 可失敗構(gòu)造器的參數(shù)名和參數(shù)類型,不能與其它非可失敗構(gòu)造器的參數(shù)名,及其參數(shù)類型相同。
嚴(yán)格來說,構(gòu)造器都不支持返回值。因為構(gòu)造器本身的作用,只是為了確保對象能被正確構(gòu)造。因此你只是用return nil表明可失敗構(gòu)造器構(gòu)造失敗,而不要用關(guān)鍵字return來表明構(gòu)造成功。

帶原始值的枚舉類型的可失敗構(gòu)造器

帶原始值的枚舉類型會自帶一個可失敗構(gòu)造器init?(rawValue:),該可失敗構(gòu)造器有一個名為rawValue的參數(shù),其類型和枚舉類型的原始值類型一致,如果該參數(shù)的值能夠和某個枚舉成員的原始值匹配,則該構(gòu)造器會構(gòu)造相應(yīng)的枚舉成員,否則構(gòu)造失敗

類的可失敗構(gòu)造器

值類型(也就是結(jié)構(gòu)體或枚舉)的可失敗構(gòu)造器,可以在構(gòu)造過程中的任意時間點觸發(fā)構(gòu)造失敗。甚至在屬性被初始化前。

而對類而言,可失敗構(gòu)造器只能在類引入的所有存儲型屬性被初始化后,以及構(gòu)造器代理調(diào)用完成后,才能觸發(fā)構(gòu)造失敗。

class Product {
    let name: String!
    init?(name: String) {
        self.name = name
        if name.isEmpty { return nil }
    }
}

構(gòu)造失敗的傳遞

類,結(jié)構(gòu)體,枚舉的可失敗構(gòu)造器可以橫向代理到類型中的其他可失敗構(gòu)造器。類似的,子類的可失敗構(gòu)造器也能向上代理到父類的可失敗構(gòu)造器。

class CartItem: Product {
    let quantity: Int!
    init?(name: String, quantity: Int) {
        self.quantity = quantity
        super.init(name: name)
        if quantity < 1 { return nil }
    }
}

重寫一個可失敗構(gòu)造器

如同其它的構(gòu)造器,你可以在子類中重寫父類的可失敗構(gòu)造器。或者你也可以用子類的非可失敗構(gòu)造器重寫一個父類的可失敗構(gòu)造器。這使你可以定義一個不會構(gòu)造失敗的子類,即使父類的構(gòu)造器允許構(gòu)造失敗。

ps: 你可以用非可失敗構(gòu)造器重寫可失敗構(gòu)造器,但反過來卻不行。

當(dāng)你用子類的非可失敗構(gòu)造器重寫父類的可失敗構(gòu)造器時,向上代理到父類的可失敗構(gòu)造器的唯一方式是對父類的可失敗構(gòu)造器的返回值進行強制解包。

可失敗構(gòu)造器 init!

你可以在init?中代理到init!,反之亦然。你也可以用init?重寫init!,反之亦然。你還可以用init代理到init!,不過,一旦init!構(gòu)造失敗,則會觸發(fā)一個斷言。

必要構(gòu)造器

在類的構(gòu)造器前添加required修飾符表明所有該類的子類都必須實現(xiàn)該構(gòu)造器:

class SomeClass {
    required init() {
        // 構(gòu)造器的實現(xiàn)代碼
    }
}

在子類重寫父類的必要構(gòu)造器時,必須在子類的構(gòu)造器前也添加required修飾符,表明該構(gòu)造器要求也應(yīng)用于繼承鏈后面的子類。在重寫父類中必要的指定構(gòu)造器時,不需要添加override修飾符


class SomeSubclass: SomeClass {
    required init() {
        // 構(gòu)造器的實現(xiàn)代碼
    }
}

ps: 如果子類繼承的構(gòu)造器能滿足必要構(gòu)造器的要求,則無須在子類中顯式提供必要構(gòu)造器的實現(xiàn)。

通過閉包或函數(shù)設(shè)置屬性的默認值

如果某個存儲型屬性的默認值需要一些定制或設(shè)置,你可以使用閉包或全局函數(shù)為其提供定制的默認值。每當(dāng)某個屬性所在類型的新實例被創(chuàng)建時,對應(yīng)的閉包或函數(shù)會被調(diào)用,而它們的返回值會當(dāng)做默認值賦值給這個屬性。

這種類型的閉包或函數(shù)通常會創(chuàng)建一個跟屬性類型相同的臨時變量,然后修改它的值以滿足預(yù)期的初始狀態(tài),最后返回這個臨時變量,作為屬性的默認值。

class SomeClass {
    let someProperty: SomeType = {
        // 在這個閉包中給 someProperty 創(chuàng)建一個默認值
        // someValue 必須和 SomeType 類型相同
        return someValue
    }()
}

ps: 如果你使用閉包來初始化屬性,請記住在閉包執(zhí)行時,實例的其它部分都還沒有初始化。這意味著你不能在閉包里訪問其它屬性,即使這些屬性有默認值。同樣,你也不能使用隱式的self屬性,或者調(diào)用任何實例方法。

例:

struct Checkerboard {
    let boardColors: [Bool] = {
        var temporaryBoard = [Bool]()
        var isBlack = false
        for i in 1...10 {
            for j in 1...10 {
                temporaryBoard.append(isBlack)
                isBlack = !isBlack
            }
            isBlack = !isBlack
        }
        return temporaryBoard
    }()
    func squareIsBlackAtRow(row: Int, column: Int) -> Bool {
        return boardColors[(row * 10) + column]
    }
}
let board = Checkerboard()
print(board.squareIsBlackAtRow(0, column: 1))
// 打印 "true"
print(board.squareIsBlackAtRow(9, column: 9))
// 打印 "false"

要點總結(jié)

有兩點疑惑:

class Product {
    let name: String!
    init?(name: String) {
        self.name = name
        if name.isEmpty { return nil }
    }
}

The Product class defined above is very similar to the Animal structure seen eariler.The Product class has a constant name property that must not be allowed to take an empty string value.To enforce this requirement,the Product class uses a failable initializer to ensure that the propety's value is nonempty before allowing initialization to succeed.
However,Product is a class,not a structure.This means that unlike Animal,any failable initializer for the Product class must provide an initial value for the name property before triggering an intialization failure.
In the example above,the name property of the Product class is defined as having an implicitly unwrapped optional string type(String!).Because it is of an optional type,this means that the name property has a default value of nil before it is assigned a specific value during initialization.This default value of nil in turn means that all of the properties introduced by the Product class have a valid initial value.As a result,the failable intializer for Product can trigger an initialization failure at the start of the intializer if it is passed an empty string,before assigning a specific value to the name property within the initializer.

以上的代碼片段和描述都是從書上摘錄的。令我疑惑的是,根據(jù)描述來看,再init?的方法體里,self.name = name應(yīng)該放到 return nil下面去。意思是說optional在構(gòu)造過程的初期是默認為nil,因此在構(gòu)造過程的開始時期就會觸發(fā)failure intializer。但實際情況是必須先給name一個初始值才能完成構(gòu)造過程,因為根據(jù)安全檢查1,首先要對本類新引進的存儲屬性初始化,然后安全檢查2,才會調(diào)用父類構(gòu)造器完成初始化,這樣看來,可失敗構(gòu)造器都是在完成所有構(gòu)造后才對。在xcode里也跑了一下,雖然上面的代碼是可以執(zhí)行的。但從運行效果上來看,應(yīng)該是先完成了initialization,才進行的可失敗判斷。

Conversely,if you write a subclass initializer that matches a superclass convenience initializer,that superclass convenience initializer can never be called directly by your subclass,as per the rules described above in Initializer Delegation For Class Types.Therefore, your subclass is not (strictly speaking)providing an override of the superclass initializer.As a result,you do not write the override modifier when providing a matching implementation of a superclass convenience initializer.

對于這段描述,我個人的理解:
第一遍的理解:(后面有第二遍看到這里時的新理解)
子類的convenience initializer為什么在嚴(yán)格意義上沒有提供一個對父類convenience initializer的override?因為父類的convenience initializer并不一定會被子類繼承(只有在某種情況下,也就是子類實現(xiàn)了所有父類的designated initializer才會觸發(fā)自動繼承),所以當(dāng)子類沒有繼承該方法,而你要給該方法加一個override是不對的。在繼承了之后加override才是對的。這樣的話就是說有時候是override了,有時候不是override了。那么swift就干脆說這個地方不用寫override啦,就給大家省事了,你就不用去分析什么時候該寫override,什么時候不該寫override。編譯器也省得去校驗啦。故此而有了這句話。

第二次看到這里的時候又有的新的理解:如前面一句所說,superclass的convenience initializer并不是直接的被subclass掉用。仔細推敲了一下這句話。普通的方法繼承可能是父類和子類里的那個方法實際上是同一個方法(即,地址空間是同一個)而自動繼承過來的convenience initializer并不和父類是同一個地址空間,而是單獨給子類開了一個地址空間,雖然函數(shù)體是一樣的。這個猜想等到實際理解了編譯器的override和方法繼承原理之后再來確定。強烈感覺第二個解釋是對的,第一個解釋略勉強.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,384評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,330評論 2 377

推薦閱讀更多精彩內(nèi)容

  • 本章將會介紹 存儲屬性的初始賦值自定義構(gòu)造過程默認構(gòu)造器值類型的構(gòu)造器代理類的繼承和構(gòu)造過程可失敗構(gòu)造器必要構(gòu)造器...
    寒橋閱讀 778評論 0 0
  • 官方文檔 初始化 Initialization是為準(zhǔn)備使用類,結(jié)構(gòu)體或者枚舉實例的一個過程。這個過程涉及了在實例里...
    hrscy閱讀 1,146評論 0 1
  • 構(gòu)造過程是使用類、結(jié)構(gòu)體或枚舉類型的實例之前的準(zhǔn)備過程。在新實例可用前必須執(zhí)行這個過程,具體操作包括設(shè)置實例中每個...
    莽原奔馬668閱讀 696評論 0 3
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,816評論 18 139
  • Jenny萬閱讀 251評論 0 0