類繼承2

重寫實例方法

在子類中,你可以重寫繼承來的實例方法或類方法,提供一個定製或替代的方法實現。

class Person{
    var name:String
    var age:Int

    func description() -> String{           //定義實例方法description
        return "\(name) 年齡是: \(age)"
    }
    class func printClass() -> (){
        print("Person 打印...")             //靜態方法不能訪問實例屬性
    }
    init(name:String, age:Int){
        self.name = name
        self.age = age
    }
}
class Student:Person{
    var school:String

    convenience init(){
        self.init(name:"Tony", age:18, school:"四川師範大學")
    }
    init(name:String, age:Int, school:String){
        self.school = school
        super.init(name:name, age:age)
    }
    override func description() -> String {                //在子類中重寫方法
        print("父類打印 \(super.description())")            //調用父類方法,super代指父類
        return "\(name) 年齡是: \(age), 所在學校: \(school)。"
    }
    override class func printClass() ->(){            //重寫靜態方法
        print("Student 打印...")
    }
}

let student1 = Student()
print("學生1: \(student1.description())")

Person.printClass()
Student.printClass()

//輸出結果:
//父類打印 Tony 年齡是:18
//學生1:Tony 年齡是:18,所在學校:清華大學。
//Person 打印...
//Student 打印...

重寫靜態方法

靜態方法使用class或static關鍵字,但是使用哪一個要看子類中是否重寫該方法。class修飾的靜態方法可以被重寫,static關鍵字的就不能。

class Account{
    var owner:String = "Tony"       //賬戶名

    //class不能換成static
    class func interestBy(amount:Double) -> Double{    //定義靜態方法
        return 0.08886 * amount
    }
}

class TermAccount:Account{     //定期賬戶
    //class可以換成static
    override class func interestBy(amount:Double) -> Double{    //重寫靜態方法 這裏的class可以換成static 除非在TermAccount的子類重寫interestBy
        return 0.09 * amount
    }
}
//調用靜態方法
print(Account.interestBy(10_000.00))
print(TermAccount.interestBy(10_000.00))

下標重寫

對下標的重寫同子類屬性重寫一樣也是重寫下標的getter和setter訪問器

class DoubleDimensionalArray{

    let rows:Int, columns:Int
    var grid:[Int]
    init(rows:Int, columns:Int){
        self.rows = rows
        self.columns = columns
        grid = Array(repeating:0, count:rows * columns)
    }
    subscript(row:Int , col:Int)->Int{         //定義下標
        get{
            return grid[(row * columns) + col]
        }
        set{
            grid[(row * columns) + col] = newValue
        }
    }
}

class SquareMatrix:DoubleDimensionalArray{  //類的繼承
    override subscript(row:Int, col:Int)->Int{  //重寫父類下標
        get{
            return super.grid[(row * columns) + col]
        }
        set{
            super.grid[(row * columns) + col] = newValue * newValue//給父類grid屬性附值
        }
    }
}

var ary2 = SquareMatrix(rows: 5, columns: 5)

for var i in 0..<5{
    for var j in 0..<5{
        ary2[i, j] = i + j
    }
}

for var i in 0..<5{
    for var j in 0..<5{
        print("\t \(ary2[i, j])", terminator:" ")
    }
    print("\n")
}

使用final關鍵字

我們可以在類的定義中使用final關鍵字聲明類、屬性、方法和下標。final聲明的類不能被繼承,final聲明的屬性、方法、和下標不能被重寫。

final class Person{ //聲明final ,說明Person類不能被繼承
    var name:String
    final var age:Int

    final func description() -> String{
        return "\(name) 年齡是: \(age)"
    }
    final class func printClass() -> (){
        print("Person 打印...")
    }
    init(name:String, age:Int){
        self.name = name
        self.age = age
    }
}
class Student:Person{            //報錯
    var school:String

    convenience init(){
        self.init(name: "Tony", age:18, school:"清華大學")
    }

    init(name:String, age:Int, school:String){
        self.school = school
        super.init(name:name, age:age)
    }

    override func description() -> String {    //報錯
        print("父類打印 \(super.description())")
        return "\(name) 年齡是: \(age), 所在學校: \(school)。"
    }

    override class func printClass() -> (){   //報錯
        print("Student 打印...")
    }

    override var age:Int{  //報錯
        get{
            return super.age
        }
        set{
            super.age = newValue < 8 ? 8: newValue
        }
    }
}

類型檢查與轉換

定義一個類的繼承

class Person{
    var name:String
    var age:Int

    func description() -> String{
        return "\(name) 年齡是: \(age)"
    }
    convenience init(){//便利構造函數
        self.init(name: "Tony")//調用本類的第二個(其他)便利構造函數
        self.age = 19
    }
    convenience init(name:String){//便利構造函數
        self.init(name: name, age:8)//調用同一類(下面)的指定構造函數
    }
    init(name:String, age:Int){//指定構造函數
        self.name = name
        self.age = age
    }
}

class Student:Person{
    var school:String
    init (name:String, age:Int, school:String){//指定構造函數
        self.school = school
        super.init(name:name, age:age)//調用Person中的指定構造函數
    }
}

class Worker:Person{
    var factory:String
    init(name:String, age:Int, factory:String){
        self.factory = factory
        super.init(name:name, age:age)
    }
}

使用is進行類型檢查,它可以判斷一個實例是否是某個類的類型。如果實例是目標類型,結果返回true,否則返回false

let student1 = Student(name:"Tom", age:18, school:"清華大學")
let student2 = Student(name: "Ben", age: 28, school: "北京大學")
let student3 = Student(name: "Tony", age: 38, school: "香港大學")

let worker1 = Worker(name: "Tom", age: 18, factory: "鋼廠")
let worker2 = Worker(name: "Ben", age: 20, factory: "電廠")

let people = [student1, student2, student3, worker1, worker2]//把實例放進數組集合中

var studentCount = 0
var workerCount = 0

for item in people{      //用循環判斷其屬於哪個子類
    if item is Worker{
        workerCount = workerCount + 1
    }else if item is Student{
        studentCount = studentCount + 1
    }
}
print("工人人數: \(workerCount), 學生人數: \(studentCount)。")

使用as、as!和as?進行類型轉換

某類型的一個常量或變量可能在幕後實際上屬於一個子類。當確定是這種情況時,你可以嘗試向下轉到它的子類型,用類型轉換操作符(as? 或 as!)。
因爲向下轉型可能會失敗,類型轉型操作符帶有兩種不同形式。條件形式(conditional form)as? 返回一個你試圖向下轉成的類型的可選值(optional value)。強制形式 as! 把試圖向下轉型和強制解包(force-unwraps)轉換結果結合爲一個操作。
//當你不確定向下轉型可以成功時,用類型轉換的條件形式(as?)。條件形式的類型轉換總是返回一個可選值(optional value),並且若下轉是不可能的,可選值將是 nil。這使你能夠檢查向下轉型是否成功。只有你可以確定向下轉型一定會成功時,才使用強制形式(as!)。當你試圖向下轉型爲一個不正確的類型時,強制形式的類型轉換會觸發一個運行時錯誤。

let p1:Person = Student(name: "Tom", age: 20, school: "清華大學")
let p2:Person = Worker(name: "Tom", age: 18, factory: "鋼廠")
let p3:Person = Person(name: "Tom", age: 28)
let p4:Student = Student(name: "Ben", age: 40, school: "北京大學")
let p5:Worker = Worker(name: "Tony", age: 28, factory: "電廠")

創建了實例,p1、p4是Student實例,p2、p5是Work實例,p3是Person實例
類型轉換有兩個方向:向下轉型——將父類類型轉換爲子類類型,向上轉型——將子類類型轉換爲父類類型。通常情況下的類型轉換都是向下轉型
as操作符在類中僅僅只用於向上轉型,很少用.還可以進行模式匹配

let p41:Person = p4 as Person//向上轉型
let p41:Person = p4

將Student類型的p4轉化爲Person類型是向上轉型,向上轉型通常可以省略as Person部分。

as!操作符可以應用於三種情況:將非可選類型爲非可選類型/將可選類型爲非可選類型/將可選類型爲可選類型

//1.將非可選類型爲非可選類型
let p11 = p1 as! Student
//let p111 = p2 as! Student  //報錯  在轉換過程中不能轉換爲目標類型
//2.將可選類型爲非可選類型
let p6 :Person? = Student(name: "Tom", age: 20, school: "清華大學")
let p12 = p6 as! Student//報錯 p6爲nil  as!在轉換過程對可選址進行拆包 

//3.將可選類型爲可選類型
let p13 = p6 as! Student?//可選類型轉換爲可選類型

as?操作符可以應用於兩種情況:將非可選類型爲可選類型, 將可選爲可選

//向上轉型,使用as?
//將非可選類型爲可選類型
let p21 = p1 as? Student
let p211 = p2 as? Student
print(p21)
print(p211)
//將可選爲可選
let p7 :Person? = Student(name: "Tom", age: 20, school: "清華大學")
let p22 = p7 as? Student?
print(p7)
print(p22)

var arr = [p1, p2, p3, p4, p5]
var i:Int = 1
for item in arr{
    if let m = item as? Worker{
        print("Worker factory: \(m.factory)")
    }else if let n = item as? Student{
        print("Student school: \(n.school)")
    }
    i += 1
}


let stud1 = arr[0] as? Student //它是Student可選類型,具體使用時往往還需要拆包
print(stud1)
print(stud1!.school)

let woker1 = arr[1] as! Worker
print(woker1)
print(woker1.name)

所以我們在使用as?操作符進行類型轉換時你最好採用可選綁定方式,也就是將轉換語句放到if或while語句中

兩種不確定的類型:Any類型和AnyObject類型

AnyObject:任何類的類型, Any:任何類型

let people1:[Person] = [student1, student2, student3, worker1, worker2]
let people2:[AnyObject] = [student1, student2, student3, worker1, worker2]
let people3:[Any] = [student1,student2,student3, worker1, worker2]

for item in people2{
    if let Student = item as? Student{
        print("Student school: \(Student.school)")
    }else if let Worker = item as? Worker{
        print("Worker factory: \(Worker.factory)")
    }
}
let w1:AnyObject = arr[1] as! Worker

使用Any類型來和混合的不同類型一起工作,包括函數類型和非類類型

var things = [Any]()//創建了一個可以存儲Any類型的數組
things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Student(name: "Tina", age: 10, school: "四川師範大學"))
things.append({ (name: String) -> String in "Hello, \(name)" })

print("\n")

for thing in things {
    switch thing {
    case 0 as Int:
        print("zero as an Int")
    case 0 as Double:
        print("zero as a Double")
    case let someInt as Int:
        print("an integer value of \(someInt)")
    case let someDouble as Double where someDouble > 0:
        print("a positive double value of \(someDouble)")
    case is Double:
        print("some other double value that I don't want to print")
    case let someString as String:
        print("a string value of \"\(someString)\"")
    case let (x, y) as (Double, Double):
        print("an (x, y) point at \(x), \(y)")
    case let stu as Student:
        print("a student name: '\(stu.name)', age: \(stu.age), school: \(stu.school)")
    case let stringConverter as (String) -> String:
        print(stringConverter("Michael"))
    default:
        print("something else")
    }
}

原則上若能夠使用具體的數據類型,則儘量不要使用AnyObject類型,更要少考慮使用Any類型。從集合取出這些實例時,請儘可能地將AnyObject或Any類型轉換爲特定類型,然後在進行接下來的操作

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章