前言java
本文的目的並不是是想挑起語言之爭,而是但願經過客觀地分析每一種主流語言的能力,辨明其長短,讓程序員可以揚長避短,有效地使用各類語言。讓各類語言可以各安其位,爲你更好的服務。python
程序員應當成爲語言的主人,而不是語言的奴隸。linux
正文程序員
這裏,我將比較一下幾種主流編程語言:C,C++,Java,.NET,Ruby,JavaScript。web
其餘主流編程語言,如Pascal,Delphi,我不太熟悉。但願熟悉的朋友可以補全對這些語言的評價。算法
至於Basic,它的版本差別很大,並且能力不太全面,這裏也不作評價。數據庫
語言特性對比表編程
C C++ Java .NET Ruby JavaScriptwindows
類型 無類型 強類型 強類型 強類型 強類型 強類型設計模式
靜態/動態 靜態 靜態 靜態檢驗類型動態解釋執行 動態 動態
支持面向過程 是 是 否 否 否 是
支持基於對象 否 是 否 是 是 是
支持範型 否 否 是 是 否 否
支持模板 否 是 否 否 否 否
支持面向對象 否 是 是 是 否 否
可能你對於我這樣的語言評價有些疑問,請首先看個人另外一篇文章基於對象和麪向對象編程範式辨析和主流編程語言中的應用 理清相關的概念。我對與面向對象和基於對象的定義和流行的定義不太同樣。
C語言優劣考
C語言由來
讓咱們先回顧一下歷史。
電腦使用CPU指令,經過寄存器,內存等物件執行計算。最先的編程,是直接使用表明CPU指令的機器碼編寫的。
直接使用二進制的數據編程,固然很容易出錯。
因而,人們後來發明了一種方法,就是使用英語單詞做爲助記符,表明各條CPU指令。
這就是彙編語言。如今,程序員可使用英語單詞進行編程,而後使用一個解釋程序,把彙編指令翻譯成機器語言,再交給計算機執行。
1970年,UNIX操做系統的研製者丹尼斯·裏奇(Dennis Ritchie)和肯·湯普遜(Ken Thompson)爲了更好地編寫操做系統,發明了C語言。
C語言比彙編語言更先進。它使用了面向過程的編程範式。同時它還是一門十分接近彙編語言,面向機器的編程語言。適合編寫操做系統和其餘直接操縱硬件硬件的編程。
面向過程編程範式
下面是我查到的過程式設計的定義:
過程式設計:
一、自上而下(top-down)的設計方式:是一個自頂向下,逐步求精的過程;
二、以main函數歸納出整個應用程序須要作的事情,而main函數由對一系列的子函數的調用組成;
main中的每個子函數均可以被精煉成更小的函數。重複這個過程,便可完成一個過程式的設計;
三、特徵是以函數爲中心,以函數做爲劃分程序的基本單位,數據每每處於從屬地位。
過程式設計的優勢:易於掌握與理解,符合人們的思惟習慣;
過程式設計的缺點:
一、不能適應問題比較複雜,或者需求常常變化的狀況;
二、數據與操做分離開,對數據與操做的修改變得很困難;
三、程序架構的依賴關係不合理:main函數依賴於子函數,子函數又依賴於更小的子函數;
而子函數每每是細節的實現,這些實現是常常變化的,形成的結構就是:
程序的核心邏輯依賴於外延的細節,一個細節上的小改動,會引發一系列的變更。
我對於面向過程編程範式是這樣理解的:
面向過程編程,就是使用函數表明處理的過程。這些函數使用的數據,要麼是參數,要麼是外部的數據。
使用函數編程,這看上去很像函數式編程。但面向過程的編程範式不一樣於函數式編程。函數式編程的函數,通常不使用外部的數據。不維持外部的狀態。這有不少優勢,但也一樣有了很大的侷限性,不似面向過程編程這樣方便。
C語言就是典型的面向過程編程語言。它經過函數抽象了過程處理。函數,就是C語言的接口。
C語言中,數據經常做爲全局的變量保存起來。這樣,使用C語言編程就很難保證其餘代碼不破壞函數依賴的數據的狀態。這是C++基於對象編程範式出現的緣由。這個咱們稍後再說。
咱們再看看C語言對機器指令的抽象。
C語言是一門十分接近彙編語言的語言。因此有人說C語言既是一門高級語言(面向過程,函數),也是一門低級語言(面向機器,直接反映計算機的實際計算過程)。
C語言使用原生類型,數組,Struct等來表示數據。C語言中,數據在內存中的表示是十分肯定的。程序員能夠充分控制。如,C語言中可使用memcpy()直接複製內存中的數據。
如今,大多數的操做系統原生函數庫,都使用C語言做爲其接口。絕大多數的語言都具有與C語言函數庫進行互操做的能力。
C語言能夠說是程序世界的世界語。
C語言的優勢
1, 面向過程開發,以函數爲中心。簡單有效。實現了簡單的接口。
2, 面向機器,讓用戶能夠徹底的操縱機器,效率較高。
C語言運行高效,普遍應用於各類計算領域。對於簡單的任務,很是有效。
C語言的缺點
1, 函數沒法有效控制須要的數據。不能保證外部狀態不變。容易出現Bug。
2, 對於機器的控制太強,也就是依賴太強。因爲過於強調效率,使用C語言編程時,更多的須要考慮機器,而不是問題自己。
因爲過於關注機器,而不是問題域自己,所以抽象能力不足。容易出現各類Bug。對於編寫大型的程序,經常力不從心。
C語言的使用方法
C語言做爲一種簡單高效的編程語言,適用於編寫簡單的程序。在編程中,應該注意揚長避短,使用面向過程的編程範式,少用對機器的依賴。
1, 使用函數編程時,應該儘可能使用函數參數傳遞狀態,少用全局數據。由於,你沒法保證全局數據不被其餘代碼改變。
這樣使用函數,叫做「純函數」。相似於函數式編程的用法。並且,使用這種方式編程,因爲不存在全局數據,在進行多線程開發時,還不須要考慮多線程問題。
2, 使用結構化的編程方式。不要賣弄技巧。
3, 函數是接口。儘可能使用函數調用,而不是直接的代碼。經過層層分層,分配職責,編寫出短小精悍,易於維護的代碼。
4, 儘管C語言是一種面向機器的語言。可是,咱們仍是應該儘可能少地依賴機器。多從問題域來考慮和抽象問題。如,少用內存假設等等。由於,咱們會使用不少種語言,C,C++,Java,C#等語言的不少語法相似。可是實際的表現,各個語言都是不一樣的。若是過度考慮C的機器特性,那麼極可能會由於記錯而編寫出錯誤的代碼。
5, 代碼,首先是給人看的。順便給機器執行!
不要到處優化代碼。只應該優化性能瓶頸。由於優化的代碼,經常表示很難看懂!
6, 應該大量使用Struct組織相關的數據。在用C語言編程時,也應該樹立類型和對象狀態的概念。把Struct做爲函數的參數傳遞數據。
C++語言優劣考
在C語言優劣考中曾經說過:C語言中,數據經常做爲全局的變量保存起來。這樣,使用C語言編程就很難保證其餘代碼不破壞函數依賴的數據的狀態。這是C++基於對象編程範式出現的緣由。
C++最初是做爲C語言的擴展出現的,最初的名字就叫「帶類的C」。後來,C++逐漸演化成一門獨立的語言。但仍是和C語言兼容。
基於對象的編程範式
基於對象的編程範式,又稱「抽象數據類型」(ADT)。
面向過程的編程範式中,函數沒法控制函數外的共享數據。這使面向過程的編程語言不能很好地編寫大型系統。爲了解決這個問題,人們發明了基於對象的編程範式。
就是把數據和處理數據的函數都封裝在一個類中。這樣,共享的數據就不會再被外部的代碼改變了!
下面是我查到的定義:
抽象數據類型(Abstract Type簡稱ADT)
ADT是指抽象數據的組織和與之相關的操做。能夠看做是數據的邏輯結構及其在邏輯結構上定義的操做。
ADT的描述規範
一個ADT可描述爲:
ADT ADT-Name{
Data://數聽說明
數據元素之間邏輯關係的描述
Operations://操做說明
Operation1://操做1,它一般可用C或C﹢﹢的函數原型來描述
Input:對輸入數據的說明
Preconditions:執行本操做前系統應知足的狀態//可看做初始條件
Process:對數據執行的操做
Output:對返回數據的說明
Postconditions:執行本操做後系統的狀態//"系統"可看做某個數據結構
Operation2://操做2
……
}//ADT
抽象數據類型能夠看做是描述問題的模型,它獨立於具體實現。它的優勢是將數據和操做封裝在一塊兒,使得用戶程序只能經過在ADT裏定義的某些操做來訪問其中的數據,從而實現了信息隱藏。在C﹢﹢中,咱們能夠用類(包括模板類)的說明來表示ADT,用類的實現來實現ADT。所以,C﹢﹢中實現的類至關因而數據的存儲結構及其在存儲結構上實現的對數據的操做。
ADT和類的概念實際上反映了程序或軟件設計的兩層抽象:ADT至關因而在概念層(或稱爲抽象層)上描述問題,而類至關因而在實現層上描述問題。此外,C﹢﹢中的類只是一個由用戶定義的普通類型,可用它來定義變量(稱爲對象或類的實例)。所以,在C﹢﹢中,最終是經過操做對象來解決實際問題的,因此咱們可將該層次看做是應用層。例如,main程序就可看做是用戶的應用程序。
C++支持多範型的開發方式:面向過程,基於對象,面向對象,模版。
C++和C語言是兼容的。所以,你徹底可使用C++編譯系統編寫C語言的程序,所以,支持面向過程編程是很天然的。
可是,使用面向過程編程,還能說是在使用C++編程嗎?
另外,須要注意,C++語言,其實是一種不一樣於C語言的新語言。在內存上,除了一些C語言的元素以外,新的語言元素並不像C那樣面向機器。
對於C++,你不能使用memcpy等內存操做的函數,極可能會出現錯誤。由於C++語言創建在一些高級概念的規範上,這些規範並無規定內存如何分配等機器方面的細節。
我在基於對象和麪向對象編程範式辨析和主流編程語言中的應用 一文中已經指出基於對象和模板是必須組合在一塊兒使用的技術。
C++中首選的編程範式是「模板支持的基於對象」的編程範式。實現靜態多態。
而後纔是面向對象的編程範式。實現動態多態。
最後是C語言風格的面向過程編程。
C++的使用方法
使用C/C++開發環境,咱們能夠同時使用C和C++開發。既然C++和C是兼容的,我認爲徹底沒有理由使用C語言,而不使用C++進行開發。
即便是很小的問題,使用C++的「模板支持的基於對象」的編程範式也是首選的開發方式。
另外一方面,在整個類庫的外部,若是咱們但願向其餘語言提供接口,那麼咱們還應當提供C語言的API函數做爲接口。
C語言是程序世界的世界語。
使用C++的基本類型,struct,STL庫的Vector,STL的string::c_str()等均可以獲得C語言兼容的接口。還不能使用異常。由於C語言不支持異常,並且C++自己的異常,在不一樣的編譯器中也可能不兼容。
總之
1,使用C++開發,只在外部接口中使用C語言開發。使用「模板支持的基於對象」的編程範式,或者面向對象的編程範式。不要使用面向過程的編程範式。
2,儘可能把代碼放到類中,而不是使用全局或者命名空間的變量。
3,儘可能不要使用操做符重載。
4,必須注意到C++不像C語言那樣面向機器,不能對C++對象的內存佈局進行假設。不能根據內存內的數據直接構建對象。不要進行內存操做。
5,C++仍是很面向機器的。不少語言規則都規定了內存的佈局,必須按照規則定義、初始化等等。這和Java,.NET,Ruby等語言不一樣。用慣高級語言的程序員特別須要注意C++和C對程序員的繁瑣要求。
C/C++的設計哲學中,始終把本身做爲一門系統編程語言,針對機器進行了不少優化。所以,對於人,就很不照顧了。不少規則很不人性化。但沒辦法,你必須適應它們!
它們就是爲了高效而生的。它們就是彙編的替代者。
Java語言優劣考
Java是一門靜態強類型面向對象的編程語言。它是C++和Smalltalk取長補短的產物。
Java是靜態編譯的強類型語言。你必須聲明變量的類型,以便編譯器可以檢查代碼的類型是否正確。這和C++是相同的。Java是一門類型很是安全的編程語言。
Java只支持一種編程範式:面向對象編程範式。對於過期的面向過程編程範式並不支持。也不支持基於對象的編程範式,也沒有模板。
緣由多是,當java在90年代中期剛剛誕生時,面向過程的編程已被唾棄。而C++的基於對象的編程方式,因爲沒有和模板相互結合,而名聲掃地。C++對於面向對象的編程範式的支持又比較差。
因而,汲取經驗教訓以後, Java做爲一門純正的面向對象編程語言誕生了。
Java使用面向對象的編程範式實現了動態多態,實現了抽象化的編程方式。取得了巨大的成功。
Java語言中,除了基本類型是值類型以外,沒有任何值類型,你也不能建立任何值類型。這樣,基於對象編程這條路就被卡死了。
雖然喪失了值類型的效率,可是也避免了基於對象編程的大量錯誤。
Java語言中全部方法也都是虛函數。這也是爲了保證純正的面向對象編程。
Java語言是靜態面向對象編程範式的頂峯。使用面向接口的抽象編程,是有效使用java開發的惟一途徑!
另外一方面,Java其實是一門動態語言。它是動態解釋執行的。和Ruby,JavaScript等同樣。
這使java具有了運行時的靈活性。能夠實現自省,反射等C++等傳統靜態語言沒法實現的功能。
.NET語言優劣考
.NET是java的兄弟。是微軟由於被Sun排除在java以外而開發的一套語言。主要包括C#,VB.net,C++/CLI等語言。
它的設計理念基本和java相同,也是一個支持靜態面向對象編程範式的平臺。
對於.NET語言平臺,我選擇C#和C++/CLI這兩種語言進行論述。VB.NET和C#相似,這裏就再也不多說了。
C#
C#.net還支持值類型,也就是基於對象的編程範式。(固然,.NET框架也是支持值類型的)
C#.net的泛型類型替換是在運行時執行的。對於引用類型(在堆內存中建立實例的類型),它使用類型強制轉換,而不是C++模板的源代碼生成來實現參數化類型。
對於值類型,則使用相似於C++模板的MSIL中間代碼生成機制實現。
順便提一下,java的泛型實現和C#的機制相似。也是使用強制類型轉換實現。並且,Java中沒有值類型,也不能對基本類型進行泛型操做,所以沒有C#和C++中的源代碼擴張問題。
可是,老實說,java的泛型機制確實太弱了!
C#語言首選的是面向對象編程範式。C#也可使用泛型支持的基於對象的編程範式。
使用值類型,對於用慣面向對象編程範式的C#和java程序員來講有必定的難度。並且,提高的效率也並不很高。
同時,在語法層面上,C# 泛型是實現參數化類型的更簡單方法,不具備 C++ 模板的複雜性。此外,C# 並不嘗試提供 C++ 模板所提供的全部功能。
所以,C#泛型支持的基於對象編程要比模板支持的基於對象的編程要弱不少。
理念上,泛型編程有些不三不四,有着太強的面向對象編程的氣味。
C#中,使用泛型支持的基於對象的編程範式不如面向對象編程範式。
我認爲,C#語言仍是應該首先使用面向對象編程範式。
C++/CLI
C++/CLI是爲了讓C++使用.NET平臺而提供的擴展機制。
.NET平臺是相似於java的靜態強類型動態執行的執行平臺。是面向對象編程範式理念的框架。
C++/CLI使用了新的語法,使用C++/CLI進行.NET開發時,相似於C#編程。
同時,也可使用模板進行C++/CLI編程。這是C++/CLI2005新增的功能。
使用C++/CLI進行.NET編程時,既可使用C#樣式的面向對象編程。也可使用模板支持的基於對象的編程範式進行開發。
能夠把模板支持的基於對象的編程範式和.NET的面向對象的編程範式結合起來使用。
C++/CLI能夠同時使用原生C++和.NET編程。若是使用.NET框架執行,那麼C++原生代碼就會存放在生成的MSIL中間代碼中,在運行時再使用C++編譯器編譯成機器碼。
.NET的互操做機制
.NET運行時自己就是使用COM編寫的,是一個COM服務器。所以,.NET和COM互操做是很是簡單的。也可使用COM技術,用C/C++直接調用.NET內的方法。
在互操做上。.NET比java實現得更好。不能從C語言調用Java方法,只能從java代碼中使用JNI調用C方法。
整體評價
.NET是java的表兄弟。又作出了一下改變。
1,定義了.NET的彙編語言。基於.NET的彙編語言能夠支持任何語言在.NET平臺上執行。Java天然也能夠做爲一個平臺。可是java平臺的設計目標就是java這一種語言,所以沒有定義彙編語言,只有java的機器碼。
2,支持值類型。雖然用處不大,可是能夠提升性能,也方便與C語言的函數庫交互。
3,泛型的實現比java強大。
4,特別是C++/CLI,具備模板*.NET運行庫的強大能力。
Ruby語言優劣考
Ruby是一種強類型的動態解釋型語言。在Ruby中一切都是對象。
使用Duck Typing「像鴨子同樣編程」的編程理念。Ruby有類型,可是變量不肯定類型。這也實現了動態的多態能力。
不象Java,.NET等靜態面向對象編程語言,不須要使用什麼都不做,僅僅表示類型的規範的接口。Ruby中使用變量時不須要聲明使用什麼接口或者類型。
任何類型均可以,只要確實有這樣的方法或者數據成員存在便可!
相似於C++的模板編程,只是C++的模板須要指定參數的類型。Ruby不須要指定變量的類型,所以不須要模板那樣的機制。
Ruby這樣不指定變量類型的語言使用起來很是靈活。
按照動態語言的觀點,既然編譯時不能徹底找出運行時的錯誤,不如不要編譯時檢查,也不要編譯。使用單元測試來尋找錯誤。
可是,C++,Java,.NET這樣的編譯時檢查類型的語言也有本身的優勢:
1,更加安全,編譯時就會發現錯誤。
2,能夠實現IDE的智能提示。而Ruby這樣的語言就不能夠。由於C++,Java的變量使用時都指定了類型,所以能夠在IDE中智能提示可能的成員。
而Ruby這樣的動態語言的變量都沒有指定類型,因此沒法爲你提供智能提示。
使用Ruby,應該使用「動態類型語言」的基於對象的編程範式,使用隱式的接口。使用的類不須要有一個共同的基類。讓各個實現類互相獨立存在就好了。記住,這是和C++的模板支持下的基於對象的編程範式相似的基於對象(ADT抽象數據類型)的編程!
不要試圖用java,C#這樣的語言的面向對象的編程思惟方式來編寫Ruby程序!
JavaScript語言優劣考
JavaScript是一門長期以來被忽視的語言。它的重要性和能力都被大大的低估了!
這是由於Java和.NET崛起以來,「靜態類型語言」的面向對象的編程範式受到普遍的推崇。做爲動態語言,函數式語言的JavaScript長期以來被廣大Java,.NET程序員視爲畸形怪胎!老實說,長久以來,我也一直是以厭惡的眼光看待它。多少次,它讓我很抓狂。
直到如今,我仍是沒有學好JavaScript。儘管JavaScript已經誕生了這麼多年,可是把JavaScript做爲一門頗有前途的動態強類型語言,函數式語言來看待仍是新鮮事物。尚未見到不少關於這方面和設計模式的研究。
周愛民的《JAVASCRIPT語言精髓與編程實踐》一書應該不錯,可是我尚未看過。
JavaScript支持面向過程的編程範式
這是JavaScript使用最普遍的一種編程範式。簡單、快速、有效。JavaScript代碼須要經過網絡傳輸到用戶瀏覽器中,所以JavaScript的使用通常都是簡單的幾個數據提交和驗證功能。若是使用Ruby那樣的動態基於對象的編程範式編碼顯得有些小題大作,又浪費帶寬。
JavaScript支持「動態類型語言」的基於對象的編程範式
若是JavaScript僅僅支持過期的面向過程的編程範式,那麼JavaScript就真的是你們心目中的雞肋了。
這些年來,廣大程序員都忽視了JavaScript也是一門動態類型語言,仍是一門函數語言!
咱們徹底能夠向Ruby那樣進行基於對象的開發。
如今,伴隨着廣大用戶對戶客戶端的效果和AJAX技術的期待。JavaScript正在完成愈來愈大的任務。正在開發和傳統語言類庫相似的龐大類庫。
如,EXT實現的用戶界面庫。和Java的Swing庫很接近。這樣巨大的系統,必需要使用基於對象的編程範式,再使用面向過程的編程範式不可想象!
把JavaScript當成Ruby來使用,這是我對你的忠告。
[題外話:
不過也許個人JavaScript技術永遠不會很高。由於雖然我愈來愈欣賞JavaScript語言的機制。可是,我對用戶界面的開發並非頗有興趣。我認爲用戶界面是小道。底層的邏輯開發才更有價值,我也更加有興趣。
]
總結
如今再來看看篇首的「語言特性對比表」,也許你可以認同我對這些語言的觀點了。
若是我須要進行原生系統開發,我會選擇使用C++,使用模板支持的基於對象的編程範式進行編碼。
若是須要給其它語言提供接口,我會用純C語言實現一些接口函數,供其它語言調用。
若是須要Java語言進行開發,確定要使用面向對象編程。須要大量使用接口,依賴於抽象。
若是須要使用.NET開發。那麼我也會使用面向對象編程範式編碼。不多使用值類型。
若是使用C++/CLI開發,我會使用模板開發原生C++程序,也會首選模板開發.NET程序。也能夠像C#那樣使用面向對象編程範式開發.NET程序。
我真的愛死模板了!這麼多年來我還一直認爲模板是個廢柴呢!
若是要編寫腳本,我會使用Ruby,「動態類型語言」的基於對象的編程範式。
Java和.NET平臺上都在引入Ruby,Python等動態語言,也許很快就能夠用它們開發Java和.NET程序了!
在瀏覽器上開發,固然得用JavaScript[好久之前,我使用VBScript這門語言—上了微軟的當了。那時覺得凡是微軟的就是好的!]。
簡單的需求,固然用面向過程範式開發。
大的項目,好比AJAX,地圖,GUI等,使用「動態類型語言」的基於對象的編程範式開發。