Ruby 类的本质
前面的章节中介绍了类的定义与实例化,本章节我们来深入探讨一下类的本质。
1. 超类
现在我们定义一两个类:Student和Person,令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会先找到他的类Student(class方法),从这个类中没有找到方法,然后继续向上找它的超类(superclass方法),从Person中找到了age和name。
这种方法查找顺序的机制,我们可以使用 祖先链 ( ancestors )来表示。
实例:
p Student.ancestors
# ---- 输出结果 ----
[Student, Person, Object, Kernel, BasicObject]
解释 :我们可以看到,祖先链是从student的类逐级向上查找的,需要注意的是,Kernel是一个模块,因为Object类include了Kernel模块,所以Kernel也会出现在祖先链里面。
在之前的学习中我们了解到,在方法名称相同的时候,include模块不会覆盖类原本的方法,而Ruby 2.0以后的perpend方法会覆盖掉类原本的方法。因此使用include或prepend引入模块会出现两种不同的祖先链。
实例:
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. 小结
本章节中的重点是:
- 所有的类都是
Object的子类。(Ruby 1.8 - 1.9 是BasicObject); - 所有的类都是
Class的实例,包括它本身; - 所有对象的方法都在类中,根据祖先链来进行查找;
 - 模块会根据
include和perpend出现在祖先链中不同的位置上。 
访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。
本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,邮箱:80764001@qq.com,予以删除。
