使能静态行为
本章节将介绍静态类型是如何工作的,并讨论Objective-c中的其它一些特性,其中就包括如何暂时规避Objecitve-C固有的动态特性。
缺省的动态行为
缺省情况下,Objective-C中的对象都是动态的实体。关于这些动态实体的任何决策都被从编译时推迟到了运行时。
■ 对象所占用的内存是在运行时由用于创建新对象的类方法动态分配的。
■ 对象的类型是在运行时动态判断的。在代码中(编译时)任何类型的对象变量都可以是id类型的,不管其真实的类是什么。id类型变量的确切类型只有在程序运行时才能判断出来。
■ 消息和方法是动态绑定的,这一点在”动态绑定“小节中有描述。由运行时的例行程序来把消息中的方法选择器和消息接受者的方法实现配对起来。
这种动态的特性使得面向对象的编程具有了更大的灵活性和更高的能力。但是这是需要付出代价的。也就是说编译器是不会对id类型变量的类型进行检查的。为了能更好地在编译时进行类型检查,也为了使得代码具有更好的自我注释性,Objective-C允许对对象进行静态的类型定义,而不仅限于使用通用的id类型。同时还允许关闭某些面向对象的特性,这样就可以把运行时的一些操作提前到编译时。
消息与函数调用相比较会慢些。与实际需要执行的操作相比,这样会带来不小的开销。使用诸如Shark或者Instruments之类的分析工具,就可以证明允许忽略Objective-C的动态特性的情况是非常少见的。
静态类型
在声明对象的时候,如果使用的是类名指针而不是id类型:
Rectangle * thisObject;
此时编译器会限制所声明的变量要么就是声明中指定的类名称类型,要么就是该类的派生类类型。在上面的示例中,thisObject就只能是某种Rectangle类型。
静态类型对象的内部结构和id类型对象是一样的。是id类型还是某种静态类型不会导致对象内部结构的不同。差别只在于不同的声明方式为编译器提供的关于该对象的信息的多少不同;或者说是对于代码阅读者所提供的关于对象信息的多少有所不同。
静态类型也不会影响到对象在运行时被处理的方式。静态类型的对象和id类型的对象是通过同样的类方法动态生成的。如果Square是Rectangle类的派生类,那么下面的代码将生成拥有所有Square对象该有的实例变量的对象,而不仅仅只是含有Rectangle类实例变量的对象:
Rectangle * thisObject = [[Square alloc] init];
发送给静态类型对象的消息也是同样会进行动态绑定的。当静态类型对象作为消息接受者时,其真实确切的类型也是在运行时作为消息处理的一部分动态决定的。发送给thisOjbect对象的display消息,将执行的是Square类中定义的方法而不是Rectangle类中的方法。
[thisObject display];
与使用id类型相比较,静态类型为编译器提供了更多的信息:
■ 在某些情况下,静态类型使得类型检查在编译阶段就可以进行了。
■ 静态类型使得对象摆脱了相同方法必须有相同返回值和参数类型的限值。
■ 静态类型使得我们可以直接使用结构的指针操作符来直接访问其实例变量。
其中前两点我们在接下来的小节中会进行讨论。第三点在“类的定义”中已经讨论过了。