[Swift]多态类型转换以及不确定类型

来源:互联网 发布:淘宝同城的怎么搜索 编辑:程序博客网 时间:2024/05/16 07:04

1. Swift的多态:

    1) 和其它语言多态描述一致,都是用父类指针或引用(这里的父类是指祖先类)指向子类的实例,然后在子类中覆盖父类的方法,利用该父类引用调用相同的方法而产生不同的行为;

    2) Swift的多态类型转换:和普通的类型转换不一样,普通的类型转换是指一般意义上的强制类型转换,但是强制类型转换不能发生在类型之间,如果使用"类名(转换对象)"则会触发相应类的构造器而不能达到转换类型的效果,因此Swift的类型转换只能发生在可以转换的两个对象之间,对于不能转换的两个对象会在编译阶段或是运行阶段报错;

Swift专门为多态之间的类型转换提供了解决方案,它的机制有严格的规则要求,首先必须要让一个父类的引用指向一个其子类的实例(这个是大前提),然后可以利用is运算符来判断该引用指向的实例是否属于某个子类,同时可以使用as运算符将该引用指向的实例正确地转化成相应的子类类型,这种转换也称为向下转换(即先将子类实例用父类包装,等到使用时再把它彻底扩展成子类);

这就好比有一个动物的序列,序列中有各种各样的动物,起初不知道该序列里每个动物都属于哪一类(比如猫科、鸟类等),但大前提是这些子类(猫科、鸟类、爬行类等都属于动物这个父类的子类),因此起初可以将这整个序列里的元素都当成动物这个基类来看待(is-a的关系,C++中解释继承关系的经典形容),然后逐个取出序列里的元素判断其具体属于哪个子类(是猫科呢还是鸟类等),这是就使用is来判断,如果确实属于猫科,则使用as操作符将一般性的动物类的猫转化成具体的猫科类,这样就可以使用猫所具有但动物所不具有的功能(基类引用只能访问基类的属性以及实现多态,但不能访问子类的新增部分);

    3) 首先看一个多态的例子:

class A {    func show() {        println("A")    }}class B: A {    override func show() {        println("B")    }}var a = A()a.show() //  Aa = B()a.show() // B


2. Swift的多态类型转换:

    1) 即is和as两个操作符的运用;

    2) 还是强调那句,这两个操作符的使用必须严格遵守之前讲过的规则:必须要让一个父类的引用指向一个其子类的实例,然后再对该引用用is判断是否属于某个具体的子类或用as将其转换成某个具体的子类类型;

    3) is的使用:

class A {    }class B: A {    }class C: A {    }var cnt_b = 0, cnt_c = 0// 都是A的子类因此发生多态,obj的类型为Alet obj = [B(), B(), C(), C(), B()]for item in obj {    if item is B { // 注意is的左边的类型必须是右边类型的父类!否则就报错!        cnt_b++    }    else if item is C {        cnt_c++    }}println("cnt_c = \(cnt_c), cnt_b = \(cnt_b)") // 2 3var obj_a = A()// 只能判断一个用父类引用指向的子类实例是否属于某个子类// 不能用于判断非以上关系的实例是否属于某个类// println(obj_a is A) // Bad! 必须是父类引用指向子类实例,指向自己也不能判断,会直接报错的!// println(B() is B) // Bad! 理由同上,不能判断自己是否属于自己的类型// println(obj_a is String) // Bad!只能用于多态引用class D: B {    }var d: A = D()println(d is D) // OK! 多层继承的多态引用也行!
    4) as的使用(接上例代码):

cnt_b = 0cnt_c = 0for item in obj {    if let obj_b = item as? B { // 同样as左侧的类型必须是右侧的父类,同样两侧的类型不能相同        cnt_b++    }    else if let obj_c = item as? C {        cnt_c++    }}println("cnt_c = \(cnt_c), cnt_b = \(cnt_b)") // 2 3
!使用as时如果能转换则成功,如果不能则会抛出运行时异常,为了不抛出异常在as后加?可以起到和可选链一样的功能,只返回nil而不会那么暴力地抛出异常,同时配合let绑定可以达到一举两得的效果,相当于is判断的同时也同时实现了类型转换!


3. 两种不确定类型——Any和AnyObject:

    1) 注意Swift的不确定类型和Java的Object类不一样,它并不是所有类的基类,可以说它们并不是类,而只是一种不确定类型(类似C语言的void类型);

    2) AnyObject可以接受任何类类型数据,而Any可以接受任意类型的数据(包括AnyObject和基本类型),由于基本类型不是类类型,因此可见这两种不确定类型并不是类类型;

    3) 虽然不是类类型,但是可以使用is和as操作符,比如0 is Int或0 as Double,其实这里的,其实这里的is和as都使用Any进行重载;

    4) 整个数组整体转换(前提是数组中所有元素类型必须一样):形式是AnyOrAnyObjectArray as [SpecificType],这样就可以返回一个转换好的[SpecificType]数组了,但是不能使用可选符号?进行保护!

class A {    }class B {    }var arr: [AnyObject] = [B(), B(), B(), B(), B(), B()]for item in arr as [B] { // 这里不能写成as?或[B?],否则会报错    // 数组整体转换必须是强制而不能使用可选?,这可能是Swift不足的地方,因此这里强制要求arr中所有元素类型一致,否则就抛出运行时异常,因为不能用?保护    println("is B")}
     5) 一个Any的例子:

class A {    }class B {    }var arr: [Any] = [1, 3.923, A(), "xlkfds", B(), B(), 9 / 12, A()]for item in arr {    if let a = item as? A {        println("A")    }    else if let b = item as? B {        println("B")    }//    else if let c = item as? Any { // 不能转换成Any或AnyObject自己本身,编译器从语法上不允许这样做!//        println("haha")//    }} // A B B A


4. 类型转换在switch中的应用:

    1) 

0 0
原创粉丝点击