【關(guān)鍵詞】反射機(jī)制;元信息;抽象;數(shù)據(jù)結(jié)構(gòu)圖
反射(Reflection)的概念是由Smith在1982年首次提出的,主要是指程序可以訪問(wèn)、檢測(cè)和修改它本身狀態(tài)或行為的一種能力。
編程語(yǔ)言反射機(jī)制[1]可以自動(dòng)生成元信息,依賴這些元信息,程序可以動(dòng)態(tài)地訪問(wèn)、檢測(cè),以及修改對(duì)象。反射機(jī)制有著廣泛應(yīng)用[2],例如:持久化、配置文件導(dǎo)入導(dǎo)出,以及框架開發(fā)[3]等等,是一種既靈活又強(qiáng)大的編程語(yǔ)言特性。
元信息,也稱為元數(shù)據(jù),是描述數(shù)據(jù)的數(shù)據(jù),它提供了關(guān)于數(shù)據(jù)的基本屬性和特征的信息。元信息在計(jì)算機(jī)領(lǐng)域有著廣泛的應(yīng)用,例如:文件系統(tǒng)中,元信息通常用于描述文件的基本屬性,可能包括文件名、文件大小、創(chuàng)建日期,以及修改日期等,這些元信息有助于文件系統(tǒng)更好地管理文件;數(shù)據(jù)庫(kù)中,元信息用于描述表的結(jié)構(gòu)、類型,以及約束等信息,幫助數(shù)據(jù)庫(kù)更好地管理數(shù)據(jù)??傊?,元信息是一種非常重要的數(shù)據(jù)資源,它提供了關(guān)于數(shù)據(jù)的基本信息和特征,有助于我們更好地管理和理解數(shù)據(jù)。
元信息在反射機(jī)制中扮演著至關(guān)重要的角色,它是反射機(jī)制得以有效運(yùn)作的核心要素。反射機(jī)制允許程序在運(yùn)行時(shí)獲取和操作對(duì)象的信息,完全是基于元信息實(shí)現(xiàn)的。元信息通常包括關(guān)于對(duì)象的類型、結(jié)構(gòu)、屬性和方法等各方面的詳細(xì)描述,通過(guò)反射機(jī)制,程序可以查詢這些元信息,從而了解對(duì)象的內(nèi)部狀態(tài)和行為;同時(shí)使得程序能夠在運(yùn)行時(shí)動(dòng)態(tài)地修改對(duì)象的狀態(tài)、調(diào)用方法或
軟件開發(fā)中,存在一種如圖1所示的關(guān)系,結(jié)構(gòu)體是現(xiàn)實(shí)的抽象,元信息是結(jié)構(gòu)體的抽象,最后元信息又是自身的抽象。
C語(yǔ)言支持對(duì)現(xiàn)實(shí)的抽象,一般使用結(jié)構(gòu)體,推廣到其他類型亦可。C語(yǔ)言提供完備的類型系統(tǒng),包括:整型、浮點(diǎn)、結(jié)構(gòu)體、數(shù)組、指針、枚舉,以及聯(lián)合體等類型,并且允許數(shù)據(jù)結(jié)構(gòu)彼此以嵌套、鏈接,以及遞歸等方式組合。
基于C語(yǔ)言類型系統(tǒng)多樣的組合方式,不僅可以構(gòu)建樹型數(shù)據(jù)結(jié)構(gòu),還可以構(gòu)建更加復(fù)雜的圖狀數(shù)據(jù)結(jié)構(gòu)。數(shù)據(jù)結(jié)構(gòu)圖[4]是用來(lái)展示數(shù)據(jù)內(nèi)部結(jié)構(gòu)的,例如:圖2是list的數(shù)據(jù)結(jié)構(gòu)圖。以數(shù)據(jù)結(jié)構(gòu)圖為依據(jù),C語(yǔ)言類型可以分兩類:簡(jiǎn)單類型包括整型、浮點(diǎn)、字符,以及枚舉,在數(shù)據(jù)結(jié)構(gòu)圖中只能是邊界節(jié)點(diǎn),即被箭頭指向,不能作為箭頭起始;復(fù)合類型包括結(jié)構(gòu)體、聯(lián)合體、數(shù)組,以及指針,在圖中可以擔(dān)當(dāng)中間節(jié)點(diǎn),連接箭頭尾部。
以直接或間接實(shí)例化成變量為依據(jù),C語(yǔ)言類型可以分成兩類:可直接實(shí)例化類型包括整型、浮點(diǎn)、字符、數(shù)組,以及指針;間接實(shí)例化類型包括結(jié)構(gòu)體、聯(lián)合體,以及枚舉,例如結(jié)構(gòu)體類型不能直接實(shí)例化成結(jié)構(gòu)體變量,需要實(shí)例化成具體結(jié)構(gòu)體,即在代碼中定義結(jié)構(gòu)體,然后再實(shí)例化該具體結(jié)構(gòu)體成為變量。
但是C語(yǔ)言抽象鏈表是不完整的,缺失元信息內(nèi)容,所以不支持反射機(jī)制。元信息是結(jié)構(gòu)體的抽象,本質(zhì)是描述C語(yǔ)言類型的結(jié)構(gòu)體。元信息的設(shè)計(jì)就是,對(duì)描述各類型所需屬性的整理匯總,如下所示:
元信息既是結(jié)構(gòu)體,又是結(jié)構(gòu)體的抽象,這就不難解釋元信息可以抽象自身。
反射機(jī)制通過(guò)提供接口將元信息與程序的實(shí)際執(zhí)行過(guò)程相結(jié)合。Java常用的反射機(jī)制訪問(wèn)接口,根據(jù)不同類型提供不同函數(shù),由調(diào)用者選擇,如下所示:
publicObjectget(Object)
publicbooleangetBoolean(Object)
publicbytegetByte(Object)
publicchargetChar(Object)
publicshortgetShort(Object)
publicintgetInt(Object)
publiclonggetLong(Object)
publicfloatgetFloat(Object)
publicdoublegetDouble(Object)
publicvoidset(Object,Object)
publicvoidsetBoolean(Object,boolean)
publicvoidsetByte(Object,byte)
publicvoidsetChar(Object,char)
publicvoidsetShort(Object,short)
publicvoidsetInt(Object,int)
publicvoidsetLong(Object,long)
publicvoidsetFloat(Object,float)
publicvoidsetDouble(Object,double)
反射機(jī)制接口設(shè)計(jì)原理,是以元信息為地圖,按圖索驥訪問(wèn)變量,賦值或者獲取變量值。Java反射訪問(wèn)接口函數(shù)繁多,主要因?yàn)樵O(shè)計(jì)上用不同函數(shù)承載不同類型,而Java又具備豐富的類型系統(tǒng)。為了簡(jiǎn)化接口,本文采用了輸入輸出參數(shù)承載類型的設(shè)計(jì)策略,對(duì)外只提供了getter和setter函數(shù):函數(shù)getter輸入?yún)?shù)需要變量地址、字段路徑,以及元信息,輸出請(qǐng)求的值;函數(shù)setter輸入?yún)?shù)需要變量地址、字段路徑、元信息,以及要設(shè)置的值。由于C語(yǔ)言類型系統(tǒng)同樣豐富,不同類型的值體現(xiàn)不同的特征,若用接口函數(shù)的值參數(shù)承載類型,值參數(shù)同樣需要具備相應(yīng)的類型系統(tǒng)。本文借用JSON類型系統(tǒng),直接使用cJSON作為值參數(shù),其中cJSON是應(yīng)用廣泛的JSON庫(kù)。反射機(jī)制訪問(wèn)接口包括三大要素:變量是被賦值和獲取的主體;元信息是變量組織結(jié)構(gòu)信息地圖,根據(jù)地圖才能找到待訪問(wèn)字段;cJSON是設(shè)置或者獲取的值,自身包括待訪問(wèn)字段路徑,本文設(shè)計(jì)反射機(jī)制訪問(wèn)接口如下:
intget_each_value_of_fields(void*obj,meta_t*meta,cJSON*value)
intset_each_value_of_fields(void*obj,meta_t*meta,cJSON*value)
其中C語(yǔ)言類型系統(tǒng)與cJSON值類型系統(tǒng)映射關(guān)系如下:
程序開發(fā)過(guò)程存在多個(gè)維度:開發(fā)者維度、代碼維度,以及程序維度。開發(fā)者直接控制代碼維度,間接控制程序維度;代碼維度直接控制程序維度;程序維度自成系統(tǒng)。結(jié)構(gòu)體處于代碼維度,不可進(jìn)入程序維度,實(shí)際上只有變量才可以攜帶數(shù)據(jù),并存在于程序維度;因此只有創(chuàng)建了對(duì)應(yīng)的元信息變量的類型才支持反射,所以不僅需要抽象出元信息結(jié)構(gòu)體,也需要為其創(chuàng)建元信息變量。本文將這些抽象出來(lái)的元信息結(jié)構(gòu)體稱為元結(jié)構(gòu)體,是元信息的抽象;把元結(jié)構(gòu)體實(shí)例化的變量稱為元變量,是元信息的載體。
將變量補(bǔ)充到抽象鏈圖中,如圖3所示:實(shí)例化了結(jié)構(gòu)體的變量,描述現(xiàn)實(shí)對(duì)象的基本屬性;實(shí)例化了抽象結(jié)構(gòu)體的元信息的變量,描述了結(jié)構(gòu)體的基本屬性;實(shí)例化了抽象元信息的元信息的變量,描述了元信息的基本屬性;元信息的自描述屬性,阻止了抽象鏈的無(wú)限增長(zhǎng)。
C語(yǔ)言不支持反射機(jī)制,元信息在程序維度不存在,它存在于代碼維度,受開發(fā)者維度控制;如何在程序維度獲取元信息,是創(chuàng)建元信息的方法要解決的本質(zhì)問(wèn)題。創(chuàng)建元信息,就是創(chuàng)建元變量,可用于創(chuàng)建其他類型變量的方式,都適用于創(chuàng)建元變量;最簡(jiǎn)單方式就是直接定義變量,然后開發(fā)者負(fù)責(zé)根據(jù)待反射結(jié)構(gòu)體對(duì)各個(gè)字段進(jìn)行初始化,整個(gè)過(guò)程是靜態(tài)的,由開發(fā)者控制,語(yǔ)言級(jí)別沒(méi)有提供任何輔助。
本文的簡(jiǎn)單反射機(jī)制,實(shí)現(xiàn)了C語(yǔ)言結(jié)構(gòu)體定義代碼解析器,可以解析結(jié)構(gòu)體定義的字符串,生成相應(yīng)的元變量;還提供了若干宏接口,簡(jiǎn)化創(chuàng)建元信息過(guò)程,設(shè)計(jì)函數(shù)和宏如下:
本文實(shí)現(xiàn)的C語(yǔ)言簡(jiǎn)單反射機(jī)制,可以應(yīng)用到各種場(chǎng)景,例如:配置文件導(dǎo)入導(dǎo)出、生成監(jiān)控報(bào)表、序列化,以及restful接口實(shí)現(xiàn)等;并且極大簡(jiǎn)化了其開發(fā)難度,例如:配置文件導(dǎo)入導(dǎo)出模塊結(jié)構(gòu)如圖4所示,首先根據(jù)配置需求編寫配置結(jié)構(gòu)體,然后為配置結(jié)構(gòu)體創(chuàng)建元變量,接著實(shí)例化配置結(jié)構(gòu)體成為配置變量,最后就可以通過(guò)getter/setter簡(jiǎn)單地實(shí)現(xiàn)配置文件導(dǎo)入導(dǎo)出。
本文實(shí)現(xiàn)的C語(yǔ)言簡(jiǎn)單反射機(jī)制,提供了基本的反射功能,具備較廣泛的應(yīng)用場(chǎng)景。但簡(jiǎn)單反射機(jī)制還有很多待改進(jìn)地方,例如:不支持?jǐn)?shù)據(jù)結(jié)構(gòu)圖存在回環(huán)結(jié)構(gòu)情況;尚不支持位段類型,位段是一種特殊類型,它委托給其他類型用于訪問(wèn),但不支持地址操作,而自身只做位數(shù)限制。