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() // A
a = 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的类型为A
let 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 3
var 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 = 0
cnt_c = 0
for 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)