# 类、方法与元类:行为放在哪里 > 原书依据:第 3 章和第 5 章,印刷页 9–12、21–25,PDF 页 20–23、32–36。 ## 状态的可见范围 | 名称 | 用途 | 阅读时应问 | | --- | --- | --- | | 实例变量 | 每个实例自己的状态槽位 | 是否继承自父类? | | 类变量 | 由类及相关子类共享的绑定 | 是否存在跨实例影响? | | 全局变量 | 经系统字典访问的绑定 | 是否形成隐含依赖? | | 池变量 | 多个类共享的变量集合 | 类定义引用了哪个池? | | 参数、临时变量 | 一次方法或块计算的局部名称 | 生命周期与可赋值规则是什么? | 原书第 5 章明确限制对方法参数再赋值。本教程沿用不修改参数的写法,不把其他实现的语法扩展套回原书。 ## 用一个小类串起语法 以下为本文编写的历史风格定义。类定义在 Browser 或相应定义工具中提交;后续方法分别安装在实例侧,不是把整段当作 Workspace 表达式执行。 ```smalltalk Object subclass: #StudyCounter instanceVariableNames: 'count' classVariableNames: '' poolDictionaries: '' category: 'Study-Examples' ``` 实例侧方法: ```smalltalk initialize count := 0 ``` ```smalltalk increment count := count + 1 ``` ```smalltalk value ^count ``` 工作区中的使用示意: ```smalltalk | counter | counter := StudyCounter new. counter initialize. counter increment. counter value ``` 这里显式初始化,不依赖 `new` 是否自动发送 `initialize`。这些安装步骤和类定义消息需要在目标镜像核对。`increment` 没有显式返回,所以返回 `counter`;`value` 返回槽位保存的数值。 ## 方法查找 普通消息从接收者的类开始找选择子,找不到就沿父类向上查找。原书的根类为 `Object`。整个链中没有对应方法时,进入 `doesNotUnderstand:` 协议。 重写方法只改变行为的选择,不把接收者换成父类对象。`self` 始终指向当前接收者。 ## super 改变查找起点 假设 B 继承 A,C 继承 B;方法 `describe` 定义在 B 中。如果该方法发送 `super name`,查找从 A 开始,即便当前接收者是 C 的实例。若发送 `self name`,查找从接收者实际的类 C 开始。 因此 `super` 不是“父对象”。它保留同一接收者,按方法定义位置确定查找起点。 ## 实例侧与类侧 `StudyCounter new` 的接收者是类对象;`counter increment` 的接收者是它的实例。类自身也是对象,类侧方法由元类组织。 读类侧构造方法时,要检查它究竟分配实例、初始化状态还是返回缓存对象。`new` 只是发给类对象的消息,不能把它视为所有类都必须遵循的固定语法。 原书的 primitive 方法把部分操作交给虚拟机。追踪执行路径时,需区分 Smalltalk 方法体与 VM 提供的原语;本教程没有验证任何 VM 的原语源码。