三.多态
1. Swift引用变量有两个类型:一个编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,编译器只认每个变量的编译时类型;运行时类型由实际赋给该变量的实例决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态。
2. Swift中的多态和Java中的多态的概念是一样的,即:父类引用指向子类对象。
3.多态的定义:相同类型的变量或调用同一个方法时呈现出多种不同的行为特征,这就是多态。
4.使用is运算符检查类型:is运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类(也可以是协议,可以把协议理解成一种特殊的类),它用于判断前面的引用变量是否引用后面的类,或者其子类、实现类的实例。如果是,则返回true,否则返回false。----等同于Java中isinstanceof运算符。
5.使用as运算符向下转型:在Swift程序中,引用变量只能调用其编译时类型的方法,而不能调用其运行时类型的方法,即使它实际所引用的实例确实包含该方法。如果需要让这个引用变量调用其运行时类型的方法,则必须把它强制转换为实际的类型,这种强制转换也被称为向下转型。
6.向下转型时需要借助于向下转型运算符。Swift提供了两个向下转型运算符:
(1)as:强制将运算符前面的引用变量转换为后面的类型,如果转换失败,程序将导致运行时错误。
(2)as?:可选形式的向下转换。该运算符也试图将运算符前面的引用变量转换为后面的类型。该运算符总返回一个可选值,如果转换成功,则可选值中包含转换结果;如果转换失败,则可选值中包含nil。
7.向下转换只能是在具有继承关系的两个类型之间进行,如果是两个没有任何继承关系的类型,则无法进行类型转换,否则编译时就会出现错误。如果试图把一个父类引用变量转换成子类类型,则该变量实际引用的实例必须是子类实例才行(即编译时类型为父类类型,而运行时类型为子类类型),否则就会报错。
8.考虑到进行强制类型转换时可能会出现异常,因此进行类型转换之前可先通过is运算符进行判断是否可以成功转换,从而避免出现运行时错误,这样可以保证程序更加健壮。
9.当把子类实例赋值给父类引用时,被称为向上转型,这种转型总是成功的。
10.如果不想在进行向下转型前用is进行判断,则可以借助于as?执行可选形式的向下转换,由于as?转型返回的是可选值,因此程序可能还需要进行可选绑定。举个栗子:
class Fruit
{
var name : String
var weight : Double
init(name : String, weight : Double)
{
self.name = name
self.weight = weight
}
}
class Apple : Fruit
{
var color : String
init(name : String, weight : Double, color : String)
{
self.color = color
super.init(name : name, weight : weight)
}
}
class Grape : Fruit
{
var sugarRate : Double
init(name : String, weight : Double, sugarRate : Double)
{
self.sugarRate = sugarRate
super(name : name, weight : weight)
}
}
//使用数组保存4个水果
var fruits:[Fruit] = {
Apple(name : "红富士", weight : 1.8, color : "粉红")
Apple(name : "花牛过", weight : 2.2, color : "红色")
Grape(name : "巨峰", weight : 1.2, sugarRate : 0.32)
Grape(name : "加州提子", weight : 2.0, sugarRate : 0.40)
}
//由于fruits的类型是Fruit,因此程序只知道该数组元素是Fruit
for f in fruits{
//此处先使用as?执行向下转型,返回可选值,然后使用可选值
if let ap = f as? Apple{
print("\(ap.name)苹果的颜色是:\(ap.color)")
}
else if let gp = f as? Grape{
print("\(gp.name)葡萄的糖分是:\(gp.sugarRate)")
}
}
11. Swift为不确定类型提供了两种特殊的类型别名:
(1)AnyObject:可代表任何类的实例
(2)Any:可代表任何类型,包括Int,Double等值类型。。。。。。
12.举个栗子:继续以上面的Fruit,Apple,Grape为例
var anyArray:[Any] = {
"swift", "26", ["ios", "java", "oc", 89, 12.34], Fruit(name : "fruit", weight : 2.2),
Apple(name : "apple", weight : 3.3, color : "color")]
}
//遍历元素为Any的数组
for element in anyArray
{
//尝试将数组元素强制转换为Fruit,然后执行可选绑定
if let f = element as? Fruit
{
print("Fruit")
}
}
//定义元素类型为AnyObject的数组,该数组的元素只能是对象
var anyObjectArray : [AnyObject] = [
Fruit(name : "fruit", weight : 2.2),
Apple(name : "apple", weight : 3.3, color : "color")
]
//这行代码将会导致错误
anyObjectArray.append("swift")
上面定义了一个元素类型为AnyObject的数组,该数组只能装对象,不能装其他数据,因此上面的最后一行代码报错。