引言:
我接觸Java,或者說(shuō)系統(tǒng)地接觸到計(jì)算機(jī)領(lǐng)域的時(shí)間是在三個(gè)月前,但在學(xué)習(xí)及后來(lái)的應(yīng)用之中,對(duì)于Java中的“面向?qū)ο蟆钡睦斫馀c感觸逐步加深,頗覺(jué)有趣,特此一書(shū)自己的理解,恰好近日在整理三月學(xué)習(xí)的各個(gè)部分以應(yīng)對(duì)來(lái)年的校招,便想,若有時(shí)間的話,也會(huì)再將其他的部分一一闡述出自己的理解,以此自我歸納以總結(jié),至于讀者,則可以交流或者學(xué)習(xí);而我迄今所學(xué),學(xué)的是WEB,具體包括了Java,xml,servlet,ajax,orcale數(shù)據(jù)庫(kù),jdbc,html,js,jq,jsp以及struts2的框架,以及一點(diǎn)點(diǎn)Spring框架,因而所舉例子,或者視野所限,將會(huì)局限于web部分,請(qǐng)讀者自行斟酌。
正文:
你是怎么看待世界的呢?
假如你要向一個(gè)外星人(能交流卻第一次來(lái)到地球)闡述地球的存在,你將如何闡述呢?
我想這屬于世界觀的范疇,每一個(gè)人都有其獨(dú)有的認(rèn)知世界的方式,而這,也是我漸漸對(duì)于Java中“面向?qū)ο蟆碑a(chǎn)生的感悟——它提供了一種世界觀,一種試圖闡述世界運(yùn)行與組成的一種方式。
“面向?qū)ο蟆钡囊环矫嬲J(rèn)為世界是層級(jí)結(jié)構(gòu)的,并且具有一定的范圍,這類(lèi)似于數(shù)學(xué)中的集合,雖然Java中也有很多的“集合”類(lèi),但這兩者指代的東西并不相同。正如幾乎每一個(gè)在初次學(xué)習(xí)“面向?qū)ο蟆睍r(shí)所學(xué)到的一樣,任何事物都是對(duì)象,“一切皆對(duì)象”。
而蘋(píng)果是一個(gè)對(duì)象,水果是一個(gè)對(duì)象,你可以說(shuō)“蘋(píng)果”是“水果”,卻不能說(shuō)“水果”是“蘋(píng)果”,這就體現(xiàn)出了一種層級(jí)關(guān)系,一種包含的關(guān)系,一種指代范圍大小的差異,而在Java代碼的表現(xiàn)上,就是在“蘋(píng)果”繼承于“水果”的前提下,你可以用“水果”聲明一個(gè)變量,來(lái)創(chuàng)建“蘋(píng)果”對(duì)象。
而在Java中,我猜測(cè)為了保證某種合理,為了一定安全性考慮,雖然可以用“水果”來(lái)聲明“蘋(píng)果”,但是當(dāng)這么聲明之后,聲明的“水果”在表觀上將只保留“水果”的特征,而失去了“蘋(píng)果”獨(dú)有的部分,雖然其實(shí)質(zhì),就是一個(gè)“蘋(píng)果”。
在Java代碼的表現(xiàn)上,就表現(xiàn)為當(dāng)用父類(lèi)(水果)聲明變量創(chuàng)建子類(lèi)(蘋(píng)果)對(duì)象的時(shí)候,這個(gè)變量將只能被使用父類(lèi)的方法與屬性,因此當(dāng)你需要使用子類(lèi)的方法或?qū)傩詴r(shí),需要向下強(qiáng)制轉(zhuǎn)型——這通常也是用父類(lèi)聲明創(chuàng)建子類(lèi)對(duì)象后遲早要做的一件事。
這樣做的很大一部分原因是為了方法的復(fù)用,更具體的解釋下文將會(huì)講解。
而當(dāng)學(xué)到這里,假如再無(wú)聊地敲些有關(guān)的代碼,你就會(huì)發(fā)現(xiàn)一件有意思的事情——在Java代碼中,你同樣可以用實(shí)現(xiàn)的接口聲明來(lái)創(chuàng)建一個(gè)實(shí)現(xiàn)了該接口實(shí)體類(lèi)的對(duì)象,而其代碼表現(xiàn),與上述的繼承幾乎完全相同,即你只能使用聲明接口的方法,而不能使用所創(chuàng)建的子類(lèi)對(duì)象的特有方法。
也就是說(shuō),“蘋(píng)果”和“籃球”雖然是兩個(gè)看似不同的東西,但你可以用同一個(gè)“球形”聲明變量來(lái)同時(shí)創(chuàng)建這兩個(gè)似乎完全不同的對(duì)象,僅僅因?yàn)槠鋵?shí)現(xiàn)了這個(gè)“接口”。
這其實(shí)是一個(gè)能讓人接觸到本質(zhì)的發(fā)現(xiàn),通過(guò)這個(gè)發(fā)現(xiàn),你就該知道,Java所謂的“單繼承、多實(shí)現(xiàn)”的結(jié)構(gòu),并沒(méi)有看起來(lái)那樣的割裂,因?yàn)閮H以上述例子論,你其實(shí)并沒(méi)有充足的論據(jù)來(lái)說(shuō)明“球類(lèi)”不是“蘋(píng)果”或“籃球”的一個(gè)父類(lèi),而實(shí)際也確實(shí)如此,雖然“蘋(píng)果”和“籃球”看似相去甚遠(yuǎn),但總有某些共性,這共性,若從數(shù)學(xué)的集合上來(lái)將,則就是交集,而其在Java之中,則是“接口”——這接口,難道不也相當(dāng)于一種特殊的被繼承的父類(lèi)嗎?
因此,一個(gè)類(lèi)單繼承的“父類(lèi)”與多實(shí)現(xiàn)的“接口”之間,似乎就僅僅是“extends”和“implements”的區(qū)別了,這在較淺的程度上講,我其實(shí)覺(jué)得并無(wú)不妥。
當(dāng)然,這里肯定得說(shuō)明,它們之間的區(qū)別并不僅是關(guān)鍵字的區(qū)別,更有基于其特性的區(qū)別,比如說(shuō)因?yàn)榻涌谥粫?huì)寫(xiě)出抽象方法,而不會(huì)有具體實(shí)現(xiàn),接口可以繼承另一個(gè)接口,因此當(dāng)類(lèi)實(shí)現(xiàn)了接口,就需要實(shí)現(xiàn)其包含的所有抽象方法,還比如說(shuō),因?yàn)榻涌诶锊⒉荒芏x屬性,因而只是方法的封裝,而不能如父類(lèi)一般,是類(lèi)的封裝……
這也恰恰說(shuō)明了接口和父類(lèi)有所區(qū)別的必要性,因此,也只能說(shuō)其二者,也只是在較淺的程度上相似。
說(shuō)回上文所說(shuō)Java通過(guò)“類(lèi)”所提供的“層級(jí)結(jié)構(gòu)”的世界觀,這種“層級(jí)結(jié)構(gòu)”也是多維度的,具體來(lái)說(shuō),就是其不僅限于上述所舉的蘋(píng)果與籃球的例子,而是在時(shí)間上也可以抽離出類(lèi)來(lái),如Servlet類(lèi)的init和destroy方法是在不同的時(shí)期分別調(diào)用——這說(shuō)起來(lái)似乎有些繞,但我想說(shuō)的是:時(shí)間的流逝的一段時(shí)期里或者說(shuō)事物的發(fā)展過(guò)程同樣可以是對(duì)象。
而凡談及世界觀,則無(wú)形中必限定了一個(gè)最大的范圍,即“世界”,世界觀里的任何事物都超不過(guò)世界的定義,Java代碼里,對(duì)于其同樣有一個(gè)類(lèi)對(duì)應(yīng),即“Object”類(lèi),Object類(lèi)是一切類(lèi)的父類(lèi),而在Java里,稱其為“對(duì)象”。
這也是我認(rèn)為其“面向?qū)ο蟆钡暮x,當(dāng)知道這點(diǎn)后,上文所說(shuō)的“強(qiáng)制向下轉(zhuǎn)型”的優(yōu)越性及必要性就有非常好的例子來(lái)論證了,同時(shí),也提供了更多的實(shí)際意義。
因?yàn)樵凇皬?qiáng)制向下轉(zhuǎn)型”的應(yīng)用中,通常所聲明的變量類(lèi)型是Object類(lèi),這在Java的許多知識(shí)中有所體現(xiàn),我印象最深的,就是設(shè)計(jì)模式中的工廠模式,他在定義工廠方法的時(shí)候聲明的返回值類(lèi)型是Object類(lèi),就可以隨意在方法中根據(jù)條件(通常是String類(lèi)型),來(lái)返回各種類(lèi)的對(duì)象,然后當(dāng)你使用時(shí),只需強(qiáng)制向下轉(zhuǎn)型成所需的對(duì)象就可以了,這在Spring框架的IOC中也有所體現(xiàn)。
另外,Java中有“泛型”的概念,雖然我并不知道其底層的實(shí)現(xiàn),但我猜測(cè),大概也是用了這種方式,因?yàn)樗^泛型,不就可以用“Object”類(lèi)來(lái)聲明嗎?它只是缺少了向下轉(zhuǎn)型的顯式步驟,這可能是因?yàn)榈讓訋湍阕隽诉@個(gè)工作。
說(shuō)到這里,應(yīng)該可以以Java的視角來(lái)回答開(kāi)篇的兩個(gè)問(wèn)題,你是怎么看待世界的呢?Java認(rèn)為世界萬(wàn)物起于Object,并且以O(shè)bject為基類(lèi)向上發(fā)展,最終通過(guò)不同的方向,演繹出繽紛的世界,而假如要向外星人闡述一個(gè)事物的時(shí)候,Java將會(huì)一層層地闡述,分明而又清晰。
本文最后一部分,將講述我在學(xué)習(xí)“面向?qū)ο蟆睍r(shí)最疑惑的地方,那就是為何Java僅僅聲明了就好像存在了呢?比如說(shuō)當(dāng)new一個(gè)Person類(lèi)的時(shí)候,你聲明一個(gè)name的String屬性,Person就有了name,這或許還可以理解一些,可當(dāng)寫(xiě)了一個(gè)run方法,即便它是空的,這個(gè)Person就能run了,這難道不令人疑惑嗎?因?yàn)镴ava就似乎上帝一樣,說(shuō)有了光,便有了光,可Java不是上帝,它被人使用并且還能有各種各樣的實(shí)際用處,這與上帝相比,似乎又太過(guò)具體了點(diǎn)。
近一個(gè)月,我忽然想明白了這個(gè)問(wèn)題,Java的“面向?qū)ο蟆保瑲w根到底,只是一種闡述世界的方式,而不是世界,它同我兒時(shí)愛(ài)看的小說(shuō)一樣,只是闡述了世界,因此,它只需要說(shuō)有,那便有了,如同小說(shuō),說(shuō)什么就有什么,區(qū)別只是某些人的描寫(xiě)生動(dòng)些,從而更真實(shí)些罷了。
這其實(shí)也是我在學(xué)習(xí)Java時(shí)最驚喜的地方,因?yàn)槲倚〉臅r(shí)候愛(ài)看玄幻仙俠小說(shuō),小說(shuō)除了精彩的故事情節(jié)曲折外,每一部小說(shuō)想象的世界觀也是格外令人著迷的,而Java,其實(shí)也如同小說(shuō),闡述了一種世界觀,只是其中曲折的故事情節(jié),就需要我們程序員來(lái)書(shū)寫(xiě)了。
而我同樣認(rèn)為Java,或者說(shuō)計(jì)算機(jī)諸多語(yǔ)言的偉大之處,在于它提供的世界觀是開(kāi)源的,是每一個(gè)懂得其規(guī)則的人都可以使用的,這是我認(rèn)為其超越小說(shuō),或者說(shuō)文學(xué)作品(因?yàn)榧幢闶乾F(xiàn)實(shí)主義的小說(shuō),其中世界,也只是作者的世界,而非完全客觀的)的地方——文學(xué)作品的世界觀寫(xiě)出來(lái)便定了下來(lái),他人很難對(duì)其作出修改,或者使用,其世界是閉塞的,是獨(dú)屬于創(chuàng)作者的,除此之外,文學(xué)作品中世界觀的邏輯性遠(yuǎn)比不上計(jì)算機(jī)世界,但真正客觀的世界難道就真如計(jì)算機(jī)世界中這么層次分明,邏輯嚴(yán)謹(jǐn)嗎?
我有時(shí)想來(lái),恐怕也并不是。
哈,這可真算的上莊周夢(mèng)蝶般的無(wú)聊了。
2018年3月4日