Ruby 類的本質(zhì)
前面的章節(jié)中介紹了類的定義與實例化,本章節(jié)我們來深入探討一下類的本質(zhì)。
1. 超類
現(xiàn)在我們定義一兩個類:Student
和Person
,令Student
繼承Person
,然后通過調(diào)用superclass
方法來輸出它的超類。
實例:
class Person
end
class Student < Person
end
puts Student.superclass
# ---- 輸出結(jié)果 ----
Person
由上面輸出可知,超類實際上是當(dāng)前類所繼承的類。
現(xiàn)在讓我們繼續(xù)獲取Person
的超類。
實例:
puts Person.superclass
# ---- 輸出結(jié)果 ----
Object
Object
是一個特殊的類,所有的類都是Object
的子類。(在Ruby 1.8 ~ 1.9中,每個類都是BasicObject
的子類)
我們輸出Object
的超類,得到了BasicObject
,它是Ruby類結(jié)構(gòu)體系的根節(jié)點。
實例:
puts Object.superclass
# ---- 輸出結(jié)果 ----
BasicObject
2. 類實際上是對象
現(xiàn)在讓我們實例化Person
,獲得一個person對象。還記得class
方法嗎,它是獲取一個對象所屬的類的方法。
實例:
person = Person.new
puts person.class
puts Person.class
# ---- 輸出結(jié)果 ----
Person
Class
解釋:第一條輸出結(jié)果代表了person對象所屬于Person
類,同理,第二條輸出結(jié)果代表了Person
類,是Class
類的對象。
Tips:每一個類都是Class的實例,這也意味著Class類也是Class類自己的實例。
實例:
puts Class.class
# ---- 輸出結(jié)果 ----
Class
因此綜上所述,所有的類都是對象。
Tips:Class的超類是Module,所以可以說所有的類其實也是模塊。
實例:
puts Class.superclass
puts Module.superclass
# ---- 輸出結(jié)果 ----
Module
Object
3. 祖先鏈
由之前的學(xué)習(xí),我們知道了Ruby的方法都是定義在類中,調(diào)用方法前,Ruby會在對象的類中查找到那個方法,現(xiàn)在讓我們學(xué)習(xí)一下它的運作原理。
舉一個例子:
"hello".reverse
在這里,"hello"調(diào)用了reverse方法,"hello"這個字符串對象作為調(diào)用方法的對象被稱為接收者(receiver)。
現(xiàn)在我們在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
# ---- 輸出結(jié)果 ----
Andrew
18
解釋:剛剛這個例子表示了一個簡單的繼承關(guān)系。Ruby在查找方法時遵循一個先右一步再向上的原則,如剛剛的student對象,Ruby會先找到他的類Student
(class
方法),從這個類中沒有找到方法,然后繼續(xù)向上找它的超類(superclass
方法),從Person
中找到了age
和name
。
這種方法查找順序的機(jī)制,我們可以使用祖先鏈(ancestors)來表示。
實例:
p Student.ancestors
# ---- 輸出結(jié)果 ----
[Student, Person, Object, Kernel, BasicObject]
解釋:我們可以看到,祖先鏈?zhǔn)菑膕tudent的類逐級向上查找的,需要注意的是,Kernel
是一個模塊,因為Object
類include了Kernel
模塊,所以Kernel
也會出現(xiàn)在祖先鏈里面。
在之前的學(xué)習(xí)中我們了解到,在方法名稱相同的時候,include
模塊不會覆蓋類原本的方法,而Ruby 2.0以后的perpend
方法會覆蓋掉類原本的方法。因此使用include
或prepend
引入模塊會出現(xiàn)兩種不同的祖先鏈。
實例:
module A
end
module B
end
class Person
prepend A
include B
end
class Student < Person
end
p Student.ancestors
# ---- 輸出結(jié)果 ----
[Student, A, Person, B, Object, Kernel, BasicObject]
解釋:從比較容易理解的層面上,因為模塊A的優(yōu)先級比Person
更高,模塊B的優(yōu)先級比Person
低,所以當(dāng)查到Student
之后,先會去找模塊A,然后是Person
,然后是模塊B …
4. 小結(jié)
本章節(jié)中的重點是:
- 所有的類都是
Object
的子類。(Ruby 1.8 - 1.9 是BasicObject
); - 所有的類都是
Class
的實例,包括它本身; - 所有對象的方法都在類中,根據(jù)祖先鏈來進(jìn)行查找;
- 模塊會根據(jù)
include
和perpend
出現(xiàn)在祖先鏈中不同的位置上。