类机制

在许多面向类语言中,“标准库”都提供一个叫“栈”(压栈,弹出等)的数据结构,用一个 Stack 类表示。这个类拥有一组变量来存储数据,还拥有一组可公开访问的行为(“方法”),这些行为使你的代码有能力与(隐藏的)数据互动(添加或移除数据等等)。

但是在这样的语言中,你不是直接在 Stack 上操作(除非制造一个 静态的 类成员引用,但这超出了我们要讨论的范围)。Stack 类仅仅是 任何 的“栈”都会做的事情的一个抽象解释,但它本身不是一个“栈”。为了得到一个可以对之进行操作的实在的数据结构,你必须 实例化 这个 Stack 类。

建筑物

传统的”类(class)”和”实例(instance)”的比拟源自于建筑物的建造。

一个建筑师会规划出一栋建筑的所有性质:多宽,多高,在哪里有多少窗户,甚至墙壁和天花板用什么材料。在这个时候,她并不关心建筑物将会被建造在 哪里,她也不关心有 多少 这栋建筑的拷贝将被建造。

同时她也不关心这栋建筑的内容 —— 家具、墙纸、吊扇等等 —— 她仅关心建筑物含有何种结构。

她生产的建筑学上的蓝图仅仅是建筑物的“方案”。它们不实际构成我们可以实在进入其中并坐下的建筑物。为了这个任务我们需要一个建筑工人。建筑工人会拿走方案并精确地依照它们 建造 这栋建筑物。在真正的意义上,他是在将方案中意图的性质 拷贝 到物理建筑物中。

一旦完成,这栋建筑就是蓝图方案的一个物理实例,一个很可能实质完美的 拷贝。然后建筑工人就可以移动到隔壁将它再重做一遍,建造另一个 拷贝

建筑物与蓝图间的关系是间接的。你可以检视蓝图来了解建筑物是如何构造的,但对于直接考察建筑物的每一部分,仅有蓝图是不够的。如果你想打开一扇门,你不得不走进建筑物自身 —— 蓝图仅仅是为了用来 表示 门的位置而在纸上画的线条。

一个类就是一个蓝图。为了实际得到一个对象并与之互动,我们必须从类中建造(也就是实例化)某些东西。这种“构建”的最终结果是一个对象,通常称为一个“实例”,我们可以按需要直接调用它的方法,访问它的公共数据属性。

这个对象是所有在类中被描述的特性的 拷贝

你不太可能会指望走进一栋建筑之后发现,一份用于规划这栋建筑物的蓝图被裱起来挂在墙上,虽然蓝图可能在办公室的公共记录的文件中。相似地,你一般不会使用对象实例来直接访问和操作类,但是对于判定对象实例来自于 哪个类 至少是可能的。

与考虑对象实例与它源自的类的任何间接关系相比,考虑类和对象实例的直接关系更有用。一个类通过拷贝操作被实例化为对象的形式。

类机制 - 图1

如你所见,箭头由左向右,从上至下,这表示着概念上和物理上发生的拷贝操作。

构造器(Constructor)

类的实例由类的一种特殊方法构建,这个方法的名称通常与类名相同,称为 “构造器(constructor)”。这个方法的具体工作,就是初始化实例所需的所有信息(状态)。

比如,考虑下面这个类的假想代码(语法是自创的):

  1. class CoolGuy {
  2. specialTrick = nothing
  3. CoolGuy( trick ) {
  4. specialTrick = trick
  5. }
  6. showOff() {
  7. output( "Here's my trick: ", specialTrick )
  8. }
  9. }

为了 制造 一个 CoolGuy 实例,我们需要调用类的构造器:

  1. Joe = new CoolGuy( "jumping rope" )
  2. Joe.showOff() // Here's my trick: jumping rope

注意,CoolGuy 类有一个构造器 CoolGuy(),它实际上就是在我们说 new CoolGuy(..) 时调用的。我们从这个构造器拿回一个对象(类的一个实例),我们可以调用 showOff() 方法,来打印这个特定的 CoolGuy 的特殊才艺。

显然,跳绳使Joe看起来很酷。

类的构造器 属于 那个类,几乎总是和类同名。同时,构造器大多数情况下总是需要用 new 来调用,以便使语言的引擎知道你想要构建一个 新的 类的实例。