去Baidu(百度)搜索┊去Yisou(一搜)搜索┊去Google搜索┊ |
Java為什么能夠支持Reflection?答案是Java運(yùn)行時仍然擁有類型信息,它包含了這個類一切:它有哪些字段、哪些方法,各是何種保護(hù)級別等等,還有這個類依賴于哪些類。在Java中,類信息以對象的形式存放,這些對象是一種元對象,它們的類型就是Class。擁有了這些信息,無論是動態(tài)創(chuàng)建對象還是調(diào)用某些方法都是輕而易舉的。在C++中,通過RTTI(運(yùn)行時類型識別),我們也可以知道類的一些信息,但為什么C++中卻沒有Reflection,原因是類型信息不完整。RTTI這個名字本身就告訴我們,C++的類型信息是用來進(jìn)行類型識別的,因此,它也不需要其它額外的信息。并不是C++無法做到這一點(diǎn),而是C++不希望給用戶增加額外的負(fù)擔(dān)。有所得,必然有所失,因此,C++放棄了元對象。關(guān)于這一點(diǎn),C++之父Bjarne Stroustrup在他的《C++語言的設(shè)計與演化》的14.2.8節(jié)中進(jìn)行了深入的討論。
元對象是Java Reflection的物質(zhì)基礎(chǔ),那它的精神基礎(chǔ)又是什么呢?Java為什么要支持Reflection?經(jīng)過上面的討論,我們把這個問題再進(jìn)一步,為什么Java要提供元對象?
討論這個問題,我們還要拉回到十年前,那時Java剛剛來到正式登上歷史的舞臺。Java實(shí)際上誕生在這之前的數(shù)年,那時候還叫Oak,環(huán)境所限使得這一劃時代的杰作甫一出爐便被束之高閣。當(dāng)Netscape掀起了為網(wǎng)絡(luò)大戲的序幕,Java得以鳳凰涅槃,這其中很重要的一個原因就是Java是以網(wǎng)絡(luò)為中心的。
仔細(xì)觀察,我們會發(fā)現(xiàn),Java的整個基礎(chǔ)架構(gòu)的設(shè)計都是為網(wǎng)絡(luò)服務(wù)。首當(dāng)其沖的便是Java中最著名的跨平臺。其實(shí),在Java之前的年代,人們也需要考慮平臺之間的可移植性,但這種移植大多數(shù)集中在源碼一級,這也就是C語言可以流行的原因之一,在單機(jī)環(huán)境下,平臺的差異并不那么明顯。網(wǎng)絡(luò)的出現(xiàn)使平臺之間差異凸現(xiàn)出來,因?yàn)榫W(wǎng)絡(luò)可能會連接各種各樣的計算機(jī)和設(shè)備。沒錯,還有設(shè)備,你也許知道Java最初的開發(fā)是和嵌入式設(shè)備相關(guān)的。一旦應(yīng)用可以跨平臺,程序開發(fā)和后期管理維護(hù)工作將得到極大的簡化,可移植性也從源碼級晉升到二進(jìn)制級(Java字節(jié)碼)。所以,跨平臺實(shí)際上也是為了網(wǎng)絡(luò)打基礎(chǔ)。Java中另一個重要的買點(diǎn)——安全性與網(wǎng)絡(luò)之間的關(guān)系更為密切,誰都可以想出幾條理由,把二者關(guān)聯(lián)起來。
再來具體看看Java的基礎(chǔ)架構(gòu)如何對網(wǎng)絡(luò)進(jìn)行支持的。還記得Java最初是怎么吸引人的嗎?沒錯,Applet。熟悉原理的朋友都知道,Applet的運(yùn)行是把遠(yuǎn)程的類文件下載到本地來執(zhí)行的。相對于本地硬盤,網(wǎng)絡(luò)給我們的感覺就是一個字————慢。如果Java采用傳統(tǒng)可執(zhí)行文件組織方式,即一個完整的可執(zhí)行文件,把整個Applet下載下來的運(yùn)行,只怕等到花兒也謝了。Java采用的手法是把文件拆開,以類為單位進(jìn)行組織,這就是我們今天見到的class文件。這樣,執(zhí)行的過程就變成第一個類下載之后就可以運(yùn)行,大大節(jié)省了最初的等待時間。好的設(shè)計會把程序分成若干的模塊,所以,絕大多數(shù)程序不可能寫在一個類中。因此,類文件中必須包含它所用到類。對于引導(dǎo)部分,我們可以讓它以特定的方式開始執(zhí)行,比如把我們耳熟能詳?shù)膍ain方法放在特定的字節(jié),但對于沒有定法的任意方法,是沒有辦法規(guī)定的,而一個類調(diào)用另一個類的方法就是這樣隨意,因此類文件中必須包含這個類方法的信息,進(jìn)一步字段信息也會加進(jìn)來,這樣幾乎一個完整類的信息就出來了,而這些信息對應(yīng)的恰好是元對象。所以,元對象出現(xiàn)在Java基礎(chǔ)架構(gòu)中。
有了元對象,Reflection也成了一件順其自然的事情。有了Reflection,Java也就擁有了動態(tài)擴(kuò)展的能力,這樣就可以極大的提高程序的靈活性。
關(guān)于Java基礎(chǔ)結(jié)構(gòu)對網(wǎng)絡(luò)的支持還可以再說幾句。class文件經(jīng)過了精心的設(shè)計,本身相當(dāng)緊湊,其目的就是為了方便在網(wǎng)絡(luò)上傳輸,而JAR文件的出現(xiàn),其目的也是為了方便網(wǎng)絡(luò)傳輸,因?yàn)槿绻看沃粋鬏斠粋€類,大量的時間都被浪費(fèi)在建立網(wǎng)絡(luò)連接的過程中,JAR文件使得一次傳輸多個類成為可能,而且我們還知道JAR文件中的數(shù)據(jù)是經(jīng)過壓縮的,這樣可以進(jìn)一步減少下載時間。Java基礎(chǔ)架構(gòu)對網(wǎng)絡(luò)的支持,《深入Java虛擬機(jī)》(第二版)的4.3節(jié)進(jìn)行了很好闡述,有興趣不妨看一下。
對Reflection思考讓我有機(jī)會對Java本身的設(shè)計進(jìn)行深入的思考。一個好的軟件設(shè)計需要一個核心理念作為支撐,所有的一切都是圍繞核心進(jìn)行的,而對于Java,這個核心就是網(wǎng)絡(luò)。