面试题答案
一键面试类别加载过程
- 编译阶段:
- 编译器会将类别相关的信息记录到类的元数据中。这些信息包括类别定义的方法列表、属性列表(虽然属性不会真正添加实例变量,只是生成存取方法声明)等。
- 运行时加载:
- 在程序运行时,runtime会加载类别。runtime会遍历所有的类别,将类别中的方法、属性等信息合并到对应的类中。具体来说,runtime会把类别方法添加到类的方法列表头部。这样做的目的是为了让类别中的方法在调用时优先于原有类的同名方法被找到(这也是同名方法处理策略的基础)。
同名方法处理
当类别中方法与原有类中方法同名时:
- 调用优先级:类别中的方法会覆盖原有类中的同名方法。因为在运行时加载类别时,类别方法被添加到类的方法列表头部,在消息发送查找方法实现时,runtime按照方法列表从前往后查找,所以会先找到类别中的方法并调用。
潜在问题
- 意外覆盖:
- 如果多个类别都定义了与原有类同名的方法,或者不同类别之间定义了同名方法,可能会导致意外的方法覆盖。开发者可能预期调用原有类的方法,但实际调用的是类别中的方法,从而出现难以排查的逻辑错误。
- 可维护性降低:
- 由于类别可以在不同的文件中定义,当存在方法覆盖时,很难直观地从类的定义中了解所有可能被调用的方法实现。这使得代码的阅读和维护变得困难,尤其是对于大型项目,不同模块的开发者可能在不知情的情况下定义了同名方法。
- 版本兼容性:
- 当原有类的开发者更新类的实现,添加或修改了某个方法,而使用该类的开发者在类别中已经覆盖了这个方法。这可能导致新的类功能无法正确发挥作用,破坏了类的原有设计意图,同时也增加了版本升级的难度。