类继承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类型转换为特定类型,然后在进行接下来的操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值