Ruby 面向?qū)ο笤?/h1>

ruby面向?qū)ο蟪醪嚼斫?/h3>

類與對象無疑是ruby的核心,可能最開始看上去有一點(diǎn)困惑,似乎有太多的概念:類、對象、類對象、模塊、實(shí)例方法、類方法、單例類.... 太多太多,許多從事ruby開發(fā)的工程師們,大多都有其他編程語言的開發(fā)經(jīng)驗(yàn),也會借助其他語言(比如java)的面向?qū)ο罄砟顏砝斫鈘uby,大多數(shù)情況下,能認(rèn)識到的也只是千篇一律的 class、new、initialize等等,很經(jīng)典的Ruby元編程一書中,也有不少朋友覺得面向?qū)ο筮@部分的概念比較繞腦,我決定記錄并分析一下

ruby虛擬機(jī)啟動之初,提供了哪些類, 模塊或者說對象

# 我們隨意創(chuàng)建一個(gè)類
class Aoo
  def hello
    puts 'hello world'
  end
end
# 打印祖先鏈
puts Aoo.ancestors
>> [Aoo, Object, Kernel, BasicObject]
# 打印Aoo單件的祖先鏈
puts Aoo.singleton_class.ancestors
>> [#<Class:Aoo>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
# 打印祖先鏈中各個(gè)對象的類型
puts Class.class
>> Class
puts Module.class
>> Class
puts Object.class
>> Class
puts Kernel.class
>> Module
puts BasicObject.class
>> Class
puts Aoo.class
>> Class

結(jié)論:

  • Class, Module, Object, Kernel, BasicObject 這幾個(gè)對象早已被ruby虛擬機(jī)提供,并且ruby中所有對象都直接或者間接繼承了他們,眾所周知,模塊是需要通過include引入的,并非顯示繼承,不過從模塊被插入祖先鏈來看,也是一種變相的繼承,并且模塊的此種特性,可以滿足多繼承需要

疑問:

  • 為何Module.class得到的結(jié)果是Class,而Kernel.class得到的結(jié)果是Module
  • Aoo的祖先鏈和Aoo單件的祖先鏈為何差距這么大
  • 我們所謂的類,比如Aoo, Object, BasicObject,或者我們所謂的模塊,比如Module, Kernel,它們的類型要么是Class,要么是Moudle,是不是意味著這些類都是對象?
  • 祖先鏈中,Class和Module居然在Object的下方,是不是意味著它們繼承了Object?

探究原生類或者對象的繼承關(guān)系

在面向?qū)ο蟮睦碚撝校诵募匆磺薪詫ο螅瑀uby對此作出了很好的詮釋,在ruby中,不管是+ - * / 還是一個(gè)我們所說的類,都是一個(gè)對象


雖然從祖先鏈來看,頂層是BasicObject,但實(shí)際上Class、Module才是ruby最初始的核心


我們剛才用.class方法獲取對象的類型,在ruby中,只有類型是Class的才可以被繼承,模塊只能混入,不可以繼承,ruby里模塊的.class都為Module,但是Module本身是一個(gè)Class,這是ruby自身的設(shè)定


我們把類型為Class的對象,叫做類對象,也就是.class是Class的對象,更多時(shí)候,我們直接稱作類,由于Class的類型也是Class,所以Class是一個(gè)可以創(chuàng)建類對象的類對象

我們查看Class中的自有方法

# 查詢方法時(shí)帶上false參數(shù) 表示只查詢自有方法,而不查詢繼承得來的方法
puts Class.methods false
>> [] # 結(jié)論 -- Class類并沒有定義自己的類方法
puts Class.instance_methods false
>> [:allocate, :new, :superclass] # 結(jié)論 -- Class僅有3個(gè)公有實(shí)例方法,其中有創(chuàng)建對象必備的new方法
puts Class.private_methods false
>> [:inherited, :initialize]
puts Class.private_instance_methods false
>> [:inherited, :initialize]
# 結(jié)論 -- Class的私有方法中,類方法和實(shí)例方法相同,是用于對象初始化的initialize

結(jié)論:

  • Class中定義的方法很少,但是包含了面向?qū)ο蟮奶匦?/li>
  • 我們知道,Object/BasicObject的類方法中,已具備new方法(不知道的朋友可以自己打印出來看
  • new方法定義在Class中,只能從Class獲取,恰好Class中的new方法是實(shí)例方法(類的實(shí)例方法會作為對象的類方法)
  • 并且BasicObject/Object的class屬性指明了類型是Class
  • 證明Object/BasicObject..等等帶有new方法的類都是Class的對象,所以類也是對象的一種
  • 注意:Class的私有方法中,不論類方法還是實(shí)例方法都帶有構(gòu)造方法initialize,證明Class本身也是有實(shí)例化過程的(由虛擬機(jī)實(shí)例化),Class本身也是一個(gè)對象,正因?yàn)槿绱耍珻lass可以調(diào)用實(shí)例方法的new去創(chuàng)建Object
  • Class非常特殊,它的類型就是自身,即Class.class === Class,這是ruby自身設(shè)定,用于形成類型引用的閉環(huán)(下面討論)

以上根據(jù)Class的內(nèi)部方法定義,以及所有類都具有new方法,證明了所有類都是Class的對象,并且Class本身也是對象

我們再看看Module

puts Module.methods false
>> [:nesting, :constants]
puts Module.instance_methods false
>> [:freeze, :===, :==, :<=>, :<, :<=, :>, :>=, :to_s, :inspect, :included_modules, :include?, :name, :ancestors, :instance_methods, :public_instance_methods, :protected_instance_methods, :private_instance_methods, :constants, :const_get, :const_set, :const_defined?, :const_missing, :class_variables, :remove_class_variable, :class_variable_get, :class_variable_set, :class_variable_defined?, :public_constant, :private_constant, :singleton_class?, :include, :prepend, :module_exec, :class_exec, :module_eval, :class_eval, :method_defined?, :public_method_defined?, :private_method_defined?, :protected_method_defined?, :public_class_method, :private_class_method, :autoload, :autoload?, :instance_method, :public_instance_method]
puts Module.private_methods false
>> [:inherited, :initialize]
puts Module.private_instance_methods false
>> [:included, :extended, :prepended, :method_added, :method_removed, :method_undefined, :initialize_copy, :attr, :attr_reader, :attr_writer, :attr_accessor, :initialize, :initialize_clone, :remove_const, :append_features, :extend_object, :prepend_features, :refine, :using, :remove_method, :undef_method, :alias_method, :public, :protected, :private, :module_function, :define_method]

結(jié)論:

  • Module中,私有類方法帶有構(gòu)造方法initialize,證明Module本身也是有實(shí)例化過程的(由虛擬機(jī)實(shí)例化),Module本身也是一個(gè)對象
  • Module中定義了大量在面向?qū)ο笾谐S貌僮鳎梢钥醋鍪敲嫦驅(qū)ο蟮闹饕獙?shí)現(xiàn)
  • 我們知道,Class雖然自己只有幾個(gè)方法,但是繼承而來的方法卻很多,如果你打印出來看的話,和Module中提供的方法基本一致,所以:Class繼承了Module

以上總結(jié),Class和Module都是由虛擬機(jī)實(shí)例化的對象,既是對象也是類,他們是虛擬機(jī)初始階段提供的核心

在虛擬機(jī)已提供Class和Module的前提下,就可以開始正常的對象創(chuàng)建和繼承了,ruby以此為基礎(chǔ),又創(chuàng)建了Kernel模塊,BasicObject, Object

  • Kernel -- 定義了大量常用工具方法比如輸入輸出之類的,通過Module.new創(chuàng)建
  • BasicObject -- 基本是個(gè)空的類,可以作為潔凈室,通過Class.new創(chuàng)建
  • Object -- 該類作為我們自定義類的基類,暴露給我們使用, 通過Class.new創(chuàng)建

疑問:

  • Module哪來new方法,雖然它和Class一樣,有虛擬機(jī)幫助實(shí)例化,既是類也是對象,但是Module不管類方法還是實(shí)例方法都沒有new,它得從Class中繼承到new方法才行,然而剛才已經(jīng)證明Class繼承了Module

Ruby核心對象的繼承方式,其實(shí)是一個(gè)環(huán)

簡單示例

Module要想獲取new,沒法繼承Class,因?yàn)镃lass已經(jīng)繼承了Module,由于他們的.class都是Class,所以可以繼承Class的實(shí)例化對象Object(也可以叫做類對象),所以Class Module Object構(gòu)成了環(huán)狀繼承關(guān)系,Module和Class中的實(shí)例方法,在Object中以類方法的形式存在(因?yàn)镺bject是Class對象),當(dāng)Module繼承Object之后,獲取了Object的類方法,換而言之,此種方式,讓自己的實(shí)例方法轉(zhuǎn)變?yōu)榱祟惙椒ǎ@3個(gè)對象間形成了方法的大范圍共享,以此為基礎(chǔ),才有了ruby各種面向?qū)ο髾C(jī)制

ruby的單件

我們回到之前提到的單件類的祖先鏈問題,對比下兩種情況下的祖先鏈

# 打印Aoo單件的祖先鏈
puts Aoo.singleton_class.ancestors
>> [#<Class:Aoo>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
# 為何Aoo的單件祖先鏈不是如下 ?????
[#<Class:#Aoo>, Class, Module, Object, Kernel, BasicObject] 
# 打印Aoo實(shí)例化對象的祖先鏈
puts Aoo.new.singleton_class.ancestors
>> [#<Class:#<Aoo:0x007fdac100dba8>>, Aoo, Object, Kernel, BasicObject] 
# 如果我們定義一個(gè)類去繼承Aoo
class Boo < Aoo
end
puts Boo.new.singleton_class.ancestors
>> [#<Class:#<Boo:0x007fdabf8d48d8>>, Boo, Aoo, Object, Kernel, BasicObject]

總結(jié):

  • 如果你平時(shí)仔細(xì)觀察,會發(fā)現(xiàn),Class的直接對象(類對象)和普通類的對象,他們單間類的祖先鏈會出現(xiàn)這兩種情況
  • 我們知道,ruby的單件是無限的,除了單件,還有單件的單件 ......,可以無限遞歸下去,所以單件類在被我們使用前,是不會自己實(shí)例化的,只有當(dāng)我們訪問單件的時(shí)候,才會實(shí)例化單件,并且這個(gè)單件也是當(dāng)前對象.class所指明類型的實(shí)例

當(dāng)你訪問對象單件的時(shí)候,絕對不僅僅只是根據(jù)類型再創(chuàng)建一個(gè)實(shí)例,比如我們訪問Aoo的單件,不僅生成了Class:Aoo,還有Class:Object,Class:BasicObject

  • 主要區(qū)別還是在于對象的.class是否是Class,也就是看它是否是一個(gè)類對象,如果當(dāng)前對象是一個(gè)類對象,證明它的單件也一定是一個(gè)Class的實(shí)例,既然都是類對象,就會有相同的繼承關(guān)系,所以Aoo單件的祖先鏈,會先列出[#<Class:Aoo>, #<Class:Object>, #<Class:BasicObject>]
  • 普通對象的的.class并非Class,對象自身并沒有所謂的繼承關(guān)系,所以普通對象的單件不涉及祖先鏈,直接就追溯到了類對象本身

最后

  • Class和Module是由虛擬機(jī)提供的特殊類,之后的一切類都由Class創(chuàng)建
  • 被new創(chuàng)建出來的,可以是對象,也可以是類對象(類),對象的.class屬性為Class的都是類對象,Class不僅可以創(chuàng)建類對象,自身也是一個(gè)類對象
  • Class中定義了創(chuàng)建對象的基本方法,比如new
  • Module中定義了大量類操作相關(guān)方法
  • Class、Module、Object、Kernel、BasicObjec這一層的初始化操作對用戶透明,將Object作為自定義類的基類
  • 類對象(類)的實(shí)例方法會作為對象的類方法
  • Class、Module、Object的繼承關(guān)系,讓他們的類方法與實(shí)例方法相同,BasicObject只是沒有混入Kernel,作為一個(gè)類對象,Class和Module中的方法是必不可少的,并不是所謂的內(nèi)部幾乎沒有方法
  • 單件是訪問的時(shí)候產(chǎn)生,并且根據(jù)繼承關(guān)系不同,產(chǎn)生的單件個(gè)數(shù)不同,會為單件生成一個(gè)完備的祖先鏈

ruby的元編程和面向?qū)ο蟮乃季S確實(shí)很繞,自己琢磨的過程中也只是略有收獲而已!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,665評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,829評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,737評論 18 399
  • 最近復(fù)習(xí)了下 ruby 對象模型的知識,參照了 Ruby Metaprogramming,于是邊看邊做筆記,還是收...
    張羽辰閱讀 536評論 0 4
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,757評論 0 9
  • 下周Guns n' Roses就要來維也納巡演了! 于是這兩天上下班路上開始重溫他們所有的專輯,今天聽到這首耳聞能...
    天休問閱讀 558評論 0 1