[objc 解释]:类和元类
翻译参考链接:[objc 解释]:类和元类
英文原文:[objc explain]: Classes and metaclasses
objc系列文章
http://www.sealiesoftware.com/blog/archive/index.html
Objective-C is a class-based object system. Each object is an instance of some class; the object's isa pointer points to its class. That class describes the object's data: allocation size and ivar types and layout. The class also describes the object's behavior: the selectors it responds to and instance methods it implements.
The class's method list is the set of instance methods, the selectors that the object responds to. When you send a message to an instance, objc_msgSend() looks through the method list of that object's class (and superclasses, if any) to decide what method to call.
Each Objective-C class is also an object. It has an isa pointer and other data, and can respond to selectors. When you call a "class method" like [NSObject alloc], you are actually sending a message to that class object.
Since a class is an object, it must be an instance of some other class: a metaclass. The metaclass is the description of the class object, just like the class is the description of ordinary instances. In particular, the metaclass's method list is the class methods: the selectors that the class object responds to. When you send a message to a class - an instance of a metaclass - objc_msgSend() looks through the method list of the metaclass (and its superclasses, if any) to decide what method to call. Class methods are described by the metaclass on behalf of the class object, just like instance methods are described by the class on behalf of the instance objects.
What about the metaclass? Is it metaclasses all the way down? No. A metaclass is an instance of the root class's metaclass; the root metaclass is itself an instance of the root metaclass. The isa chain ends in a cycle here: instance to class to metaclass to root metaclass to itself. The behavior of metaclass isa pointers rarely matters, since in the real world nobody sends messages to metaclass objects.
More important is the superclass of a metaclass. The metaclass's superclass chain parallels the class's superclass chain, so class methods are inherited in parallel with instance methods. And the root metaclass's superclass is the root class, so each class object responds to the root class's instance methods. In the end, a class object is an instance of (a subclass of) the root class, just like any other object.
Confused? The diagram may help. Remember, when a message is sent to any object, the method lookup starts with that object's isa pointer, then continues up the superclass chain. "Instance methods" are defined by the class, and "class methods" are defined by the metaclass plus the root (non-meta) class.
In proper computer science language theory, a class and metaclass hierarchy can be more free-form, with deeper metaclass chains and multiple classes instantiated from any single metaclass. Objective-C uses metaclasses for practical goals like class methods, but otherwise tends to hide metaclasses. For example, [NSObject class] is identical to [NSObject self], even though in formal terms it ought to return the metaclass that NSObject->isa points to. The Objective-C language is a set of practical compromises; here it limits the class schema before it gets too, well, meta.
下面是翻译:
Object-C 是基于类的对象系统。每一个对象都是一些类的实例;这个对象的 isa 指针指向它所属的类。该类描述这个对象的数据信息:内存分配大小(allocation size)和实例变量的类型(ivar types )与布局(layout)。这个类也描述了对象的行为:它能够响应的选择器(selectors)和它实现的实例方法(instance methods)。
类的方法列表是一个实例方法的集合(instance methods),是对象响应的选择器(selectors)。当你向一个实例发送一条消息,objc_msgSend()
查询对象所属类(和它的父类,如果有)的方法列表,去决定调用哪个方法。
每个 Object-C 类也是一个对象。它有一个 isa 指针和其他数据,并且可以响应选择器。当你调用一个“类方法”,例如:[NSObject alloc],你实际上是向类对象发送了一条消息。
由于一个类是一个对象,它肯定也是其他类的实例,这个类是元类(metaclass)。元类是关于类对象的描述,就像类是普通实例对象的描述一样。实际上,元类的方法列表正是类方法(该类对象响应的选择器)。当你向一个类(元类的实例)发送消息,objc_msgSend()查询元类(和它的父类,如果有)的方法列表,去决定调用哪个方法。元类为类对象描述类方法,就像类为实例对象描述实例方法一样。
元类?元类链是一直向下的吗?不是,一个元类是根元类的实例;根元类是它自身的实例。isa 指针链以一个环结束:实例指向类-指向元类-指向根元类-到自身。元类的 isa 指针并不重要,因为在现实世界中,没人会向元类对象发送消息。
元类的父类就要更重要了。元类的父类链平行于类的父类链,因此类方法跟实例方法一样被继承。并且根元类的父类是根类,因此每个类对象都响应根类的实例方法。最后,一个类对象就像其他对象一样是根类的实例(或子类)。
晕了吧?这个图肯定会帮助你。记住,当一个消息被发送到任何对象,都会从对象的 isa 指针开始寻找应该调用的方法,然后继续沿着父类链向上寻找。“实例方法”被类定义,“类方法”被元类和根类(非元类)定义。
在合理的电脑科学语言理论中,一个类和元类的层次结构可以是更*的形式,像更深的元类链以及任何单一的元类实例化多个类。Object-C 使用元类实现了类方法这样的实际目的,但在其他情况下趋向于隐藏元类。例如,[NSObject class]等价于[NSObject self],尽管按正常的理解它应该返回 NSObject->isa 指向的元类。Object-C 语言有一些实际情况的妥协,在这里,它不能得到类的实际结构,元类。
上一篇: 面向对象之关于类和对象的创建和使用
下一篇: 什么是类?对象?类与对象的关系是什么?
推荐阅读
-
设计模式学习 (IV) - UML 中的类图和类图之间的关系
-
经度和纬度聚类:聚类算法比较
-
springboot 配置 mybatis 代码生成器 mybatis 生成器 快速生成实体类 POJO、映射器接口和映射器接口映射文件
-
iOS 反向 (IV)-APP Smashing Shell 和类转储工具的使用
-
C++ 中的类和对象 (I)
-
35 岁实现财务*,腾讯程序员手握2300万提前退休?-1000万房产、1000万腾讯股票、加上300万的现金,一共2300万的财产。有网友算了一笔账,假设1000万的房产用于自住,剩下1300万资产按照平均税后20-50万不等进行计算,大约花上26-60年左右的时间才能赚到这笔钱。也就是说,普通人可能奋斗一辈子,才能赚到这笔钱。在很多人还在为中年危机而惶惶不可终日的时候,有的人的35岁,就已经安全着陆,试问哪个打工人不羡慕?但问题是有这样财富积累必然有像样的实力做靠山。没有人可以不劳而获。 看到这里,肯定有人说,那么对于普通人来说,卷可能真就成了唯一的出路。但是卷也有轻松的卷,“偷懒”的卷法,对于程序员而言,刨除掉一时无法改掉的开会传统占用的大部分时间,如何把有限的时间和精力放在真正重要的架构设计、需求设计上,而不是重复的造*,编码、改bug、手动测试。因此在科技改变生活的今天,学会使用AI工具成为程序员们的必备技能。 以全栈式全自动的软件开发工具飞算SoFlu软件机器人为例,作为全球首款面向微服务架构设计和最佳实践的软件机器人,SoFlu软件机器人改变了原来手工编码的作业模式,通过可视化拖拽方式以及参数配置就能实现等同于编写复杂代码的业务逻辑,在设计业务逻辑时就完成了微服务应用开发,做到“业务即图,图即代码”,实现“软件开发,十倍提效”。 而作为飞算SoFlu软件机器人的一个重要组成部分,FuncGPT(慧函数)支持所有类型函数创建。通过自然语言描述Java函数需求,实时生成高质量、高可读性的Java函数代码。生成代码可直接复制到IDEA,或一键导入Java全自动开发工具函数库。 FuncGPT(慧函数)具有五大核心能力: ● 自然语言:通过自然语言即可生成函数,降低软件开发门槛。 ● 秒级函数开发:全自动秒级开发函数,秒级完成,效率千倍提升。 ● 一站式函数开发应用:函数生成即可直接应用,效率、安全有保障。 ● 质量可靠:生成的函数代码符合业界规范、具备良好的可读性,符合最优解。 ● 灵活生成:可以根据开发人员的具体需求生成并支持调整和修改。 以“将文件流转换为File对象”这个需求为例,以下是FuncGPT(慧函数)秒级生成的代码: / 类名:FileConverter // 函数名:convertStreamToFile // 函数功能:将文件流转换为File对象 // POM依赖包:无 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class FileConverter { /** * 将文件流转换为File对象 * @param inputStream 文件流 * @param filePath 文件路径 * @param fileName 文件名 * @return 转换后的File对象 * @throws IOException 如果发生I/O异常 */ public static File convertStreamToFile(InputStream inputStream, String filePath, String fileName) throws IOException { File file = new File(filePath + File.separator + fileName); // 创建File对象 try (FileOutputStream outputStream = new FileOutputStream(file)) { // 创建文件输出流 byte buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { // 从文件流读取数据并写入文件 outputStream.write(buffer, 0, bytesRead); } } return file; // 返回转换后的File对象 } } // 函数示例 // 将文件流转换为File对象示例 // 入参:inputStream,文件流 // 入参:filePath,文件路径 // 入参:fileName,文件名 // 出参:file,转换后的File对象 // 调用示例: // InputStream inputStream = new FileInputStream("example.txt"); // String filePath = "C:\\Users\\User\\Documents"; // String fileName = "example.txt"; // File file = FileConverter.convertStreamToFile(inputStream, filePath, fileName); // System.out.println(file.getAbsolutePath); // 输出结果:例如,将文件流转换为File对象后,文件的绝对路径为:C:\Users\User\Documents\example.txt // 则输出结果为:C:\Users\User\Documents\example.txt 通过分析,不难发现以上代码:
-
说明 css3:核心技术和案例分析2.8 结构伪类选择器
-
SpringBoot 与 MultipartFile 类相结合,实现文件上传和下载
-
Java 面试问题:解释 Java 中的并发工具类 ConcurrentHashMap 如何工作,并列举经典应用示例
-
JAVA 系列初学者参考类和对象 (2)