透過歷史聊聊C、C++和Java之間的那點(diǎn)事
一、編程語言哪家強(qiáng),先看歷史長不長
當(dāng)今世界,Java、Python、C++等編程語言橫行于互聯(lián)網(wǎng),各界程序員日夜奔忙,為改變世界的程序夢拼搏奮斗。這些高級語言如今如此之地位,不得不讓我們驚嘆。
自1946年2月14日世界上首款計(jì)算機(jī)問世,第一代計(jì)算機(jī)語言“機(jī)器語言”便誕生了,當(dāng)時(shí)的“機(jī)器語言”使用的是最原始的穿孔卡片,這種卡片上使用的語言只有那些真正的專家才能理解,這種“機(jī)器語言”是否容易理解看那個(gè)年代專家的禿頂就知道了。
“機(jī)器語言”本質(zhì)上是計(jì)算機(jī)能識別的唯一語言,而人類卻很難理解,豈一個(gè)“難”字了得。后來那些語言大師們?yōu)榱四茏屓藗兏菀桌斫?,于是便有了第二代?ldquo;匯編語言”,相比機(jī)器語言,匯編語言還是有所改良的,盡管它還是太復(fù)雜,人們在使用時(shí)很容易出錯(cuò)誤,但畢竟許多數(shù)碼已經(jīng)開始用字母來代替,這也算一大進(jìn)步了。簡單的“0、1”數(shù)碼誰也不好理解,但字母是人們能夠閱讀和拼寫的。雖然第二代計(jì)算機(jī)語言仍然是“面向機(jī)器”的語言,但它已注定成為機(jī)器語言向更高級語言進(jìn)化的橋梁。
當(dāng)計(jì)算機(jī)語言發(fā)展到第三代時(shí),就進(jìn)入了“面向人類”的語言階段。你可以閱讀、并直接用人類的語言來輸入。對我們漢語來說,目前還不能用中文漢字來輸入指令,這主要是因?yàn)橹形牡妮斎脒€沒有一個(gè)非常好的手段。第三代語言被人們稱之為“高級語言”。高級語言是一種接近于人們使用習(xí)慣的程序設(shè)計(jì)語言。它允許用英文寫計(jì)算程序,程序中所使用的運(yùn)算符號和運(yùn)算式子,都和我們?nèi)粘S玫臄?shù)學(xué)式子差不多。高級語言容易學(xué)習(xí),通用性強(qiáng),書寫出的程序比較短,便于推廣和交流,是很理想的一種程序設(shè)計(jì)語言。
二、Java的誕生
Java是SUN公司推出的一種計(jì)算機(jī)語言,先說說Java這個(gè)名字的來歷吧。
Java名稱來源于太平洋一個(gè)名叫Java的小島,該島出產(chǎn)一種味道非常美妙的咖啡。當(dāng)?shù)厝朔浅O矚g咖啡,Java的發(fā)明者Gosling在這個(gè)小島上受到了當(dāng)?shù)厝?ldquo;特殊”的照顧,讓他如癡如醉般喜歡上了咖啡的美味。Gosling認(rèn)為他發(fā)明的計(jì)算機(jī)語言是非常好的東西,起初他把他發(fā)明的語言起名為“OaK”,但是SUN公司的人發(fā)現(xiàn)已經(jīng)存在一門叫做OaK的計(jì)算機(jī)語言了,而現(xiàn)在嘗著如此美味的咖啡,從咖啡的靈感中索性起名為“Java”,流傳至今。
說實(shí)際的吧,SUN公司于1995年正式推出新一代面向?qū)ο蟮某绦蛟O(shè)計(jì)語言Java??吹矫嫦?qū)ο?,我們知道面向?qū)ο笳Z言(OOP, Object-Oriented Programming)是一類以對象作為基本程序結(jié)構(gòu)單位的程序設(shè)計(jì)語言。Java 是面向?qū)ο缶幊讨械囊环N代表性語言,但除了Java,還有C++等編程語言也是面向?qū)ο缶幊痰拇?,我們研究Java的發(fā)展歷史,肯定擺脫不了它的“競爭對手”C++,而C++又?jǐn)[脫不了C語言,索性把它們?nèi)齻€(gè)放一起描述。先看下面這張描述C、C++、Java的時(shí)間歷程圖:
單從時(shí)間上看,1973年C語言問世,然后在C的基礎(chǔ)上,1983年C++問世,C++問世的時(shí)候已經(jīng)在C語言的基礎(chǔ)上添加了面向?qū)ο蟮乃枷?,而Java是在1995年才出世的,單從C++和Java所共有的“面向?qū)ο?rdquo;這個(gè)思想上,我們也會相信它們之間肯定有故事,我們先去探索它們之間的故事吧。
三、C、C++還有Java,你們之間到底有什么故事
自1973年C語言問世后,在之后的很長一段時(shí)間,很多程序員都在用C語言,C語言很受程序員的歡迎,因?yàn)樗o當(dāng)時(shí)的程序員們編程提供了極好的便利,C語言貼近硬件、運(yùn)行極快、效率極高,這些便利條件,讓當(dāng)時(shí)的程序員們用C語言開發(fā)了很多系統(tǒng)級軟件、編譯器、數(shù)據(jù)庫、操作系統(tǒng)、網(wǎng)絡(luò)系統(tǒng)等。但世間萬物有利必有弊,C語言的弊端就在于指針和內(nèi)存管理。
雖然指針無比強(qiáng)大,能直接操作內(nèi)存,但是沒有給工具做越界的檢查,導(dǎo)致很多新手程序員輕易犯錯(cuò)。至于內(nèi)存管理,更是讓人無語,自己分配的空間,必須自己去釋放。C語言最讓人頭疼的是前面這些問題在編譯器發(fā)現(xiàn)不了,只有在程序運(yùn)行時(shí)才會突然暴露,這總會讓程序員猝不及防,手忙腳亂,總是昏天黑地地去調(diào)試。你想啊,程序員們大量的時(shí)間和寶貴的精力都浪費(fèi)在小心翼翼的處理指針和內(nèi)存分配上,程序員怎能忍受。還有一點(diǎn),C語言所謂的可移植性欺騙了好多程序員,它宣稱在一個(gè)機(jī)器上寫的程序,只要在另外一個(gè)機(jī)器上編譯就可以了,但實(shí)際上不是這樣,C語言要求程序員們要用標(biāo)準(zhǔn)的C函數(shù)庫。其次,如果遇到了一些針對特定平臺的調(diào)用,需要對每個(gè)平臺都得寫一份,如果有一點(diǎn)點(diǎn)的小錯(cuò)誤,就會導(dǎo)致編譯失敗。這些算是C語言的一些弊端吧。
到了1983年,貝爾實(shí)驗(yàn)室推出了一門新的編程語言C++,添加了面向?qū)ο蟮墓δ?,兼容C,有靜態(tài)類型檢查,性能也很好。 其實(shí)最早,C++ 相對于C語言的基礎(chǔ)上就添加了面向?qū)ο蠛湍K的思想,這也可以理解成 C++ 中兩個(gè)加號的來歷。然而,C++ 在面向?qū)ο笊献龅牟⒉皇翘茫热?C++ 支持多繼承,多繼承會引發(fā)不確定性。
再如,C++ 還支持指針,指針直接對內(nèi)存底層操作,雖然效率高,危險(xiǎn)系數(shù)卻非常高。例如,一個(gè)簡單的病毒程序就可以靠指針完成:你通過一個(gè)程序的中給指針隨機(jī)賦值,能夠獲取到訪問不屬于本程序執(zhí)行空間的其他空間的權(quán)限,那么這也就是一個(gè)計(jì)算機(jī)病毒。(當(dāng)然,真正的病毒不可能那么簡單,但這是基本特性)。所以后來的 Java 在 C++ 的基礎(chǔ)上移除了指針,增加了引用,提高了安全性。
說穿了,C++只不過是C語言的升級版,但C語言中存在的弊端在C++中依舊存在,直到后來,1995年,Java被SUN公司正式推出,Java的一些特性很受程序員們的歡迎,比如再也沒有C語言那樣的指針,再也不用考慮內(nèi)存管理,而且還有真正的可移植性,編寫一次,到處運(yùn)行,為了實(shí)現(xiàn)跨平臺,Java中在操作系統(tǒng)和應(yīng)用程序之間增加了一個(gè)抽象層叫Java虛擬機(jī)。用Java寫的程序都跑在虛擬機(jī)上,除非個(gè)別情況,都不用看到操作系統(tǒng)。
剛才提到了一個(gè)專業(yè)術(shù)語叫跨平臺,我來解釋一下:跨平臺概念是軟件開發(fā)中一個(gè)重要的概念,是指即不依賴于操作系統(tǒng),也不信賴硬件環(huán)境。在一個(gè)操作系統(tǒng)下開發(fā)的應(yīng)用,放到另一個(gè)操作系統(tǒng)下依然可以運(yùn)行。
Java的跨平臺是相對于其他編程語言而言的,通過Java語言編寫的應(yīng)用程序在不同的系統(tǒng)平臺上都可以運(yùn)行。一般的高級語言如果要在不同的平臺上運(yùn)行,至少需要編譯成不同的目標(biāo)代碼。比如在前文中提到的C語言,在Windows系統(tǒng)上編譯的C語言程序,在Linux系統(tǒng)上是不能運(yùn)行的,而Java語言在不同平臺上運(yùn)行時(shí)不需要重新編譯。
Java跨平臺的原理:java的跨平臺是通過Java虛擬機(jī)(JVM)來實(shí)現(xiàn)的。
Java源程序想象成我們的C源程序,Java源程序(.java)編譯后生成的字節(jié)碼(.class)就相當(dāng)于C源程序編譯后的二進(jìn)制可執(zhí)行文件。JVM虛擬機(jī)相當(dāng)于計(jì)算機(jī)系統(tǒng)(操作系統(tǒng)+硬件環(huán)境),Java解釋器相當(dāng)于CPU。
- exe文件直接在Windows操作系統(tǒng)下運(yùn)行,在CPU上運(yùn)行的是機(jī)器碼(.exe文件)
- class字節(jié)碼文件是運(yùn)行在JVM虛擬機(jī)下的,在Java解釋器上運(yùn)行的是Java字節(jié)碼文件。
Java解釋器相當(dāng)于運(yùn)行Java字節(jié)碼的CPU,但該CPU不是通過硬件實(shí)現(xiàn)的,而是用軟件實(shí)現(xiàn)的。Java解釋器實(shí)際上就是特定的平臺下的一個(gè)應(yīng)用程序。只要實(shí)現(xiàn)了特定平臺下的解釋器程序,Java字節(jié)碼就能通過解釋器程序在該平臺下運(yùn)行,這是Java跨平臺的根本。當(dāng)然,并不是在所有的平臺下都有相應(yīng)的Java解釋器程序,這也是Java并不能在所有的平臺下都能運(yùn)行的原因,它只能在已實(shí)現(xiàn)了Java解釋器程序的平臺下運(yùn)行。
還有,在C++ 中,假如你寫同樣一個(gè)程序,在 Java 里面會報(bào)錯(cuò),而在 C++ 語言里面是不會報(bào)錯(cuò)的。為什么?
因?yàn)?C/C++ 語言設(shè)計(jì)的思想是:你想怎么寫程序就怎么寫,只要你的這種寫法錯(cuò)得不是很離譜,就認(rèn)為你這么寫有特殊的含義,可以通過。但 Java 不行:只要你這么寫有歧義,或者說這樣寫不太好,那么它都會報(bào)錯(cuò)。
比如 C++ 中你可以將一個(gè)浮點(diǎn)型數(shù)據(jù)賦給一個(gè)整型變量,編譯時(shí)只會警告,因?yàn)闀G失精度,但是在 Java 中這樣寫就會報(bào)錯(cuò),它在語法上就禁止你這樣寫。這就是不同的語言對同樣一個(gè)問題有不同的理解和處理方式。
由于 C++ 中大大小小的問題會導(dǎo)致不安全性,所以就在 C++ 的基礎(chǔ)上,取其精華,去其糟粕,便形成了早期的 Java 語言。直到現(xiàn)在,Java 又多了很多新的特性,比如說集合,反射,泛型,Lambda 表達(dá)式等等。
正因?yàn)閺腃語言到C++,最后再到Java 的發(fā)展歷史,使得 Java 在一定程度上繼承了多數(shù)C語言的語法,但又有一定的改變,而這些改變就是很多程序員喜歡Java的原因。
以上就是C語言、C++和Java之間的故事,要相信萬物一切皆有因果,學(xué)習(xí)要求因求果。