【问题标题】:Ruby hiding vs overridingRuby 隐藏与覆盖
【发布时间】:2015-11-28 06:41:05
【问题描述】:

我刚刚了解到,在 Java 中,覆盖和隐藏之间存在区别(静态方法是隐藏而不是覆盖),这意味着 Java 使用早期绑定和后期绑定。

是否有类似于方法隐藏的东西,或者它只是具有方法覆盖?

【问题讨论】:

    标签: ruby overriding method-hiding


    【解决方案1】:

    Java 有三种不同的“方法”:实例方法、静态方法和构造函数。 Ruby 只有一个:实例方法。

    在 Java 中,静态方法必须与实例方法不同,因为类不是对象。他们没有类,因此没有超类,所以没有什么可以覆盖的。在 Ruby 中,类是对象,就像任何其他对象一样,它们有一个类,它可以有一个超类,因此子类可以覆盖超类的方法。

    注意:您可能听说过 Ruby 中的类方法或单例方法。这是一个谎言。好吧,好吧,不是谎言。这是我们使用的一种方便的简写,因为“类方法”比“类对象的单例类的常规实例方法”更容易发音……但这正是它的本质。没有类方法。

    在 Ruby 中,每个对象都可以有自己的方法。这些被称为“单例方法”。类与任何其他对象一样是对象,因此它们也可以具有单例方法。当单例方法所属的对象是一个类时,我们称该方法为类方法。但这就是我们所说的,类方法和单例方法没有区别。

    实际上,在 Ruby 中,每个对象都有一个单例类。单例类与对象是 1:1 的关系:对象只有一个单例类,每个单例类只有一个实例,即它的对象。那么,当我上面说对象可以有方法并且这些方法称为单例方法时?嗯,那也是一个谎言。单例方法实际上只是标准的实例方法,恰好在对象的单例类中定义,因此可以在该对象上only调用(因为该对象是其单例类的唯一实例)。

    所以,当一个方法在单例类中定义时,我们称它为单例方法,当单例类属于一个类时,我们称它为类方法,但都是实例方法。 (顺便说一句:模块的工作方式相同。在这种情况下,它们被称为模块方法或有时称为“模块函数”。)

    对象的class 指针总是 指向它的单例类。那么对象的实际类就是单例类的superclass,即单例类的superclass指针指向对象的实际类。 (除非有mixin,它们变成了它们混入的类的超类,所以如果你把一个模块混入一个单例类,这个模块就变成了单例类的超类,而旧的超类变成了模块的超类,或者而是它包含代理类。)

    这意味着 方法查找,这是 OO 语言中最常执行的操作,变得非常简单且非常快速:抓取对象,抓取它的 class 指针,看看是否方法在那里,抓住超类指针,看看方法是否在那里,抓住超类指针......直到找到方法。

    这确实意味着反射会变得更复杂一些,但反射并不是对性能至关重要的操作。例如,如果你向一个对象询问它的​​类,你不能简单地返回 class 指针,因为那总是它的单例类,因此信息量不是很大。你必须得到超类,以及超类的超类等等,直到你最终得到一个不是单例类或包含代理类的类。

    但是方法查找本身非常简单,super 总是按照你的预期去做。

    特别是当你创建一个新类时,超类的单例类成为子类单例类的超类,这样“类方法”就如你所愿地被继承了。

    所以,回顾一下:虽然 Java 有三种不同的“方法”,它们具有不同的继承行为(实例方法被继承,静态方法不被继承,构造函数被继承但有这个 super 调用限制),Ruby 只有一。但是,它具有三种不同的类:常规类、单例类和包含代理类(在将模块混入类时创建为 mixins 的代理)。后两者在 YARV(最广泛使用的 Ruby 实现)中也称为“虚拟类”。

    最后一件事:还有所谓的“全局方法”,有时称为“全局过程”或“全局函数”。同样,正如您可能已经猜到的那样,这些不存在。当您在任何类之外定义方法时,它会隐式成为Object 的私有实例方法,因此可用于每个对象。

    [我在这里忽略了两件事:BasicObjectprepend。这些使事情有些复杂化,尤其是后者。但主要的心智模型仍然存在。]

    【讨论】:

      猜你喜欢
      • 2012-05-22
      • 1970-01-01
      • 1970-01-01
      • 2015-10-17
      • 2017-09-21
      • 2018-04-29
      • 2013-12-12
      • 2011-02-05
      • 1970-01-01
      相关资源
      最近更新 更多