首页 > 服务端语言 > Ruby 入门教程 > 32 Ruby 类的本质

Ruby 类的本质

前面的章节中介绍了类的定义与实例化,本章节我们来深入探讨一下类的本质。

1. 超类

现在我们定义一两个类:StudentPerson,令Student继承Person,然后通过调用superclass方法来输出它的超类。

实例:

class Person
end

class Student < Person
end

puts Student.superclass

# ---- 输出结果 ----
Person

由上面输出可知,超类实际上是当前类所继承的类。

现在让我们继续获取Person的超类。

实例:

puts Person.superclass

# ---- 输出结果 ----
Object

Object是一个特殊的类,所有的类都是Object的子类。(在Ruby 1.8 ~ 1.9中,每个类都是BasicObject的子类)

我们输出Object的超类,得到了BasicObject,它是Ruby类结构体系的根节点。

实例:

puts Object.superclass

# ---- 输出结果 ----
BasicObject

2. 类实际上是对象

现在让我们实例化Person,获得一个person对象。还记得class方法吗,它是获取一个对象所属的类的方法。

实例:

person = Person.new
puts person.class
puts Person.class

# ---- 输出结果 ----
Person
Class

解释 :第一条输出结果代表了person对象所属于Person类,同理,第二条输出结果代表了Person类,是Class类的对象。

Tips :每一个类都是Class的实例,这也意味着Class类也是Class类自己的实例。

实例:

puts Class.class

# ---- 输出结果 ----
Class

因此综上所述, 所有的类都是对象

Tips :Class的超类是Module,所以可以说所有的类其实也是模块。

实例:

puts Class.superclass
puts Module.superclass

# ---- 输出结果 ----
Module
Object

3. 祖先链

由之前的学习,我们知道了Ruby的方法都是定义在类中,调用方法前,Ruby会在对象的类中查找到那个方法,现在让我们学习一下它的运作原理。

举一个例子:

"hello".reverse

在这里,"hello"调用了reverse方法,"hello"这个字符串对象作为调用方法的对象被称为 接收者receiver )。

现在我们在Person中定义方法。

实例:

class Person
  def age
    18
  end

  def name
    "Andrew"
  end

end

class Student < Person
end

student = Student.new
puts student.name
puts student.age

# ---- 输出结果 ----
Andrew
18

解释 :刚刚这个例子表示了一个简单的继承关系。Ruby在查找方法时遵循一个 先右一步再向上 的原则,如刚刚的student对象,Ruby会先找到他的类Studentclass方法),从这个类中没有找到方法,然后继续向上找它的超类(superclass方法),从Person中找到了agename

这种方法查找顺序的机制,我们可以使用 祖先链ancestors )来表示。

实例:

p Student.ancestors

# ---- 输出结果 ----
[Student, Person, Object, Kernel, BasicObject]

解释 :我们可以看到,祖先链是从student的类逐级向上查找的,需要注意的是,Kernel是一个模块,因为Object类include了Kernel模块,所以Kernel也会出现在祖先链里面。

在之前的学习中我们了解到,在方法名称相同的时候,include模块不会覆盖类原本的方法,而Ruby 2.0以后的perpend方法会覆盖掉类原本的方法。因此使用includeprepend引入模块会出现两种不同的祖先链。

实例:

module A
end

module B
end

class Person
  prepend A
  include B
end

class Student < Person
end

p Student.ancestors

# ---- 输出结果 ----
[Student, A, Person, B, Object, Kernel, BasicObject]

解释 :从比较容易理解的层面上,因为模块A的优先级比Person更高,模块B的优先级比Person低,所以当查到Student之后,先会去找模块A,然后是Person,然后是模块B …

4. 小结

本章节中的重点是:

  1. 所有的类都是Object的子类。(Ruby 1.8 - 1.9 是BasicObject);
  2. 所有的类都是Class的实例,包括它本身;
  3. 所有对象的方法都在类中,根据祖先链来进行查找;
  4. 模块会根据includeperpend出现在祖先链中不同的位置上。
本文来自互联网用户投稿,不拥有所有权,该文观点仅代表作者本人,不代表本站立场。
访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。
本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,邮箱:80764001@qq.com,予以删除。
© 2023 PV138 · 站点地图 · 免责声明 · 联系我们 · 问题反馈