Ruby 隐藏与覆盖
Ruby hiding vs overriding
我刚刚了解到 Java 中覆盖和隐藏之间存在区别(静态方法是隐藏的而不是覆盖),这意味着 Java 使用早期绑定和后期绑定。
是否有类似于方法隐藏的东西,或者它只是有方法覆盖?
Java有三种不同的"methods":实例方法、静态方法和构造函数。 Ruby 只有一个:实例方法。
在 Java 中,静态方法 必须 与实例方法的行为不同,因为 classes 不是对象。他们没有 class,因此没有 superclass,所以没有什么可以覆盖。在 Ruby 中,classes 就像任何其他对象一样是对象,它们有一个 class,它可以有一个 superclass,因此 subclasses可以覆盖 superclass 方法。
注意:您可能听说过 class 方法或 Ruby 中的单例方法。这是一个谎言。好吧,好吧,不是谎言。我们使用 shorthand 很方便,因为 "class method" 比 "regular instance method of the class object's singleton class" 更容易发音……但这正是事实。没有 class 方法。
在Ruby中,每个对象都可以有自己的方法。这些被称为 "singleton methods"。 类 和其他对象一样是对象,所以它们也可以有单例方法。当单例方法所属的对象是 class 时,我们称该方法为 class 方法。但这就是我们所说的,class方法和单例方法没有区别。
实际上,在Ruby中,每个对象都有一个单例class。单例 class 与对象处于 1:1 关系:对象只有一个单例 class 并且每个单例 class 都只有一个实例,即它的对象。那么,当我上面说对象可以有方法并且那些方法被称为单例方法时?好吧,那也是一个谎言。单例方法实际上只是标准的实例方法,恰好定义在对象的单例 class 中,因此只能在该对象上调用 (因为该对象是其单例的唯一实例 class).
所以,当一个方法定义在单例class中时,我们称它为单例方法,当单例class属于一个class时,我们称它为class 方法,但它只是实例方法。 (顺便说一句:模块的工作方式相同。在这种情况下,它们被称为模块方法,有时也称为 "module functions"。)
一个对象的class
指针总是指向它的单例class。对象的actualclass则为单例class的superclass
,即单例class的[=11] =]指针指向对象的实际class。 (除非有 mixins,它成为它们混入的 class 的 superclasses,所以如果你将一个模块混合成一个单例 class,该模块就成为 superclass 的单例 class,而旧的 superclass 成为模块的 superclass,或者更确切地说,它包含代理 class。)
这意味着 方法查找,这是 OO 语言中最常执行的操作,变得非常简单而且非常快:抓住对象,抓住它的 class
指针,看有没有方法,抓取superclass指针,看有没有方法,抓取superclass指针……直到找到方法
这确实意味着反射变得有点复杂,但反射不是性能关键型操作。例如,如果你向一个对象询问它的 class,你不能简单地 return class
指针,因为它总是它的单例 class 因此不是很翔实的。你必须得到 superclass 和 superclass 的 superclass 等等,直到你得到一个 class 而不是单例 class 或包含代理 class.
但是方法查找本身非常简单,而且super
总能做到你所期望的。
特别是,当您创建一个新的 class 时,superclass 的单例 class 成为单例 class 的 superclass subclass,因此 "class methods" 会像您期望的那样被继承。
所以,回顾一下:虽然 Java 有三种不同的 "methods" 具有不同的继承行为(实例方法被继承,静态方法没有,构造函数被继承但是有这个 super
调用限制),Ruby只有一个。然而,它具有三种不同类型的 classes:常规 classes、单例 classes 和包含代理 classes(创建为 mixin 的代理,混合时一个模块变成 class)。后两者在 YARV 内部也称为 "virtual classes",是使用最广泛的 Ruby 实现。
最后一件事:还有所谓的 "global methods",有时也称为 "global procedures" 或 "global functions"。同样,正如您可能已经猜到的那样,这些并不存在。当您在任何 class 之外定义方法时,它隐式成为 Object
的私有实例方法,因此可用于每个对象。
[我在这里忽略了两件事:BasicObject
和 prepend
。这些使事情变得有些复杂,尤其是后者。但主要心智模型仍然存在。]
我刚刚了解到 Java 中覆盖和隐藏之间存在区别(静态方法是隐藏的而不是覆盖),这意味着 Java 使用早期绑定和后期绑定。
是否有类似于方法隐藏的东西,或者它只是有方法覆盖?
Java有三种不同的"methods":实例方法、静态方法和构造函数。 Ruby 只有一个:实例方法。
在 Java 中,静态方法 必须 与实例方法的行为不同,因为 classes 不是对象。他们没有 class,因此没有 superclass,所以没有什么可以覆盖。在 Ruby 中,classes 就像任何其他对象一样是对象,它们有一个 class,它可以有一个 superclass,因此 subclasses可以覆盖 superclass 方法。
注意:您可能听说过 class 方法或 Ruby 中的单例方法。这是一个谎言。好吧,好吧,不是谎言。我们使用 shorthand 很方便,因为 "class method" 比 "regular instance method of the class object's singleton class" 更容易发音……但这正是事实。没有 class 方法。
在Ruby中,每个对象都可以有自己的方法。这些被称为 "singleton methods"。 类 和其他对象一样是对象,所以它们也可以有单例方法。当单例方法所属的对象是 class 时,我们称该方法为 class 方法。但这就是我们所说的,class方法和单例方法没有区别。
实际上,在Ruby中,每个对象都有一个单例class。单例 class 与对象处于 1:1 关系:对象只有一个单例 class 并且每个单例 class 都只有一个实例,即它的对象。那么,当我上面说对象可以有方法并且那些方法被称为单例方法时?好吧,那也是一个谎言。单例方法实际上只是标准的实例方法,恰好定义在对象的单例 class 中,因此只能在该对象上调用 (因为该对象是其单例的唯一实例 class).
所以,当一个方法定义在单例class中时,我们称它为单例方法,当单例class属于一个class时,我们称它为class 方法,但它只是实例方法。 (顺便说一句:模块的工作方式相同。在这种情况下,它们被称为模块方法,有时也称为 "module functions"。)
一个对象的class
指针总是指向它的单例class。对象的actualclass则为单例class的superclass
,即单例class的[=11] =]指针指向对象的实际class。 (除非有 mixins,它成为它们混入的 class 的 superclasses,所以如果你将一个模块混合成一个单例 class,该模块就成为 superclass 的单例 class,而旧的 superclass 成为模块的 superclass,或者更确切地说,它包含代理 class。)
这意味着 方法查找,这是 OO 语言中最常执行的操作,变得非常简单而且非常快:抓住对象,抓住它的 class
指针,看有没有方法,抓取superclass指针,看有没有方法,抓取superclass指针……直到找到方法
这确实意味着反射变得有点复杂,但反射不是性能关键型操作。例如,如果你向一个对象询问它的 class,你不能简单地 return class
指针,因为它总是它的单例 class 因此不是很翔实的。你必须得到 superclass 和 superclass 的 superclass 等等,直到你得到一个 class 而不是单例 class 或包含代理 class.
但是方法查找本身非常简单,而且super
总能做到你所期望的。
特别是,当您创建一个新的 class 时,superclass 的单例 class 成为单例 class 的 superclass subclass,因此 "class methods" 会像您期望的那样被继承。
所以,回顾一下:虽然 Java 有三种不同的 "methods" 具有不同的继承行为(实例方法被继承,静态方法没有,构造函数被继承但是有这个 super
调用限制),Ruby只有一个。然而,它具有三种不同类型的 classes:常规 classes、单例 classes 和包含代理 classes(创建为 mixin 的代理,混合时一个模块变成 class)。后两者在 YARV 内部也称为 "virtual classes",是使用最广泛的 Ruby 实现。
最后一件事:还有所谓的 "global methods",有时也称为 "global procedures" 或 "global functions"。同样,正如您可能已经猜到的那样,这些并不存在。当您在任何 class 之外定义方法时,它隐式成为 Object
的私有实例方法,因此可用于每个对象。
[我在这里忽略了两件事:BasicObject
和 prepend
。这些使事情变得有些复杂,尤其是后者。但主要心智模型仍然存在。]