強(qiáng)類型語(yǔ)言
強(qiáng)類型語(yǔ)言也稱為強(qiáng)類型定義語(yǔ)言。是一種總是強(qiáng)制類型定義的語(yǔ)言,要求變量的使用要嚴(yán)格符合定義,所有變量都必須先定義后使用。
java、.NET、C++等都是強(qiáng)制類型定義的。也就是說,一旦一個(gè)變量被指定了某個(gè)數(shù)據(jù)類型,如果不經(jīng)過強(qiáng)制轉(zhuǎn)換,那么它就永遠(yuǎn)是這個(gè)數(shù)據(jù)類型了。
例如你有一個(gè)整數(shù),如果不顯式地進(jìn)行轉(zhuǎn)換,你不能將其視為一個(gè)字符串。
與其相對(duì)應(yīng)的是弱類型語(yǔ)言:數(shù)據(jù)類型可以被忽略的語(yǔ)言。它與強(qiáng)類型定義語(yǔ)言相反, 一個(gè)變量可以賦不同數(shù)據(jù)類型的值。
弱類型語(yǔ)言
弱類型語(yǔ)言也稱為弱類型定義語(yǔ)言。與強(qiáng)類型定義相反。像vb,php等就屬于弱類型語(yǔ)言·
一種類型可以被忽略的語(yǔ)言,與強(qiáng)類型定義相反。VBScript是弱類型定義的。在VBScript中,可以將字符串‘12’和整數(shù)3進(jìn)行連接得到字符串‘123’,然后可以把它看成整數(shù)123,而不需要顯示轉(zhuǎn)換。
但其實(shí)它們的類型沒有改變,VB只是在判斷出一個(gè)表達(dá)式含有不同類型的變量之后,自動(dòng)在這些變量前加了一個(gè)clong()或(int)()這樣的轉(zhuǎn)換函數(shù)而已。能做到這一點(diǎn)其實(shí)是歸功于VB的編譯器的智能化而已,這并非是VB語(yǔ)言本身的長(zhǎng)處或短處。
強(qiáng)類型語(yǔ)言和弱類型語(yǔ)言的區(qū)別
編譯型和解釋型
我們先看看編譯型,其實(shí)它和匯編語(yǔ)言是一樣的:也是有一個(gè)負(fù)責(zé)翻譯的程序來(lái)對(duì)我們的源代碼進(jìn)行轉(zhuǎn)換,生成相對(duì)應(yīng)的可執(zhí)行代碼。這個(gè)過程說得專業(yè)一點(diǎn),就稱為編譯(Compile),而負(fù)責(zé)編譯的程序自然就稱為編譯器(Compiler)。如果我們寫的程序代碼都包含在一個(gè)源文件中,那么通常編譯之后就會(huì)直接生成一個(gè)可執(zhí)行文件,我們就可以直接運(yùn)行了。但對(duì)于一個(gè)比較復(fù)雜的項(xiàng)目,為了方便管理,我們通常把代碼分散在各個(gè)源文件中,作為不同的模塊來(lái)組織。這時(shí)編譯各個(gè)文件時(shí)就會(huì)生成目標(biāo)文件(Object file)而不是前面說的可執(zhí)行文件。一般一個(gè)源文件的編譯都會(huì)對(duì)應(yīng)一個(gè)目標(biāo)文件。這些目標(biāo)文件里的內(nèi)容基本上已經(jīng)是可執(zhí)行代碼了,但由于只是整個(gè)項(xiàng)目的一部分,所以我們還不能直接運(yùn)行。待所有的源文件的編譯都大功告成,我們就可以最后把這些半成品的目標(biāo)文件“打包”成一個(gè)可執(zhí)行文件了,這個(gè)工作由另一個(gè)程序負(fù)責(zé)完成,由于此過程好像是把包含可執(zhí)行代碼的目標(biāo)文件連接裝配起來(lái),所以又稱為鏈接(Link),而負(fù)責(zé)鏈接的程序就叫……就叫鏈接程序(Linker)。鏈接程序除了鏈接目標(biāo)文件外,可能還有各種資源,像圖標(biāo)文件啊、聲音文件啊什么的,還要負(fù)責(zé)去除目標(biāo)文件之間的冗余重復(fù)代碼,等等,所以……也是挺累的。鏈接完成之后,一般就可以得到我們想要的可執(zhí)行文件了。
上面我們大概地介紹了編譯型語(yǔ)言的特點(diǎn),現(xiàn)在再看看解釋型。噢,從字面上看,“編譯”和“解釋”的確都有“翻譯”的意思,它們的區(qū)別則在于翻譯的時(shí)機(jī)安排不大一樣。打個(gè)比方:假如你打算閱讀一本外文書,而你不知道這門外語(yǔ),那么你可以找一名翻譯,給他足夠的時(shí)間讓他從頭到尾把整本書翻譯好,然后把書的母語(yǔ)版交給你閱讀;或者,你也立刻讓這名翻譯輔助你閱讀,讓他一句一句給你翻譯,如果你想往回看某個(gè)章節(jié),他也得重新給你翻譯。
兩種方式,前者就相當(dāng)于我們剛才所說的編譯型:一次把所有的代碼轉(zhuǎn)換成機(jī)器語(yǔ)言,然后寫成可執(zhí)行文件;而后者就相當(dāng)于我們要說的解釋型:在程序運(yùn)行的前一刻,還只有源程序而沒有可執(zhí)行程序;而程序每執(zhí)行到源程序的某一條指令,則會(huì)有一個(gè)稱之為解釋程序的外殼程序?qū)⒃创a轉(zhuǎn)換成二進(jìn)制代碼以供執(zhí)行,總言之,就是不斷地解釋、執(zhí)行、解釋、執(zhí)行……所以,解釋型程序是離不開解釋程序的。像早期的BASIC就是一門經(jīng)典的解釋型語(yǔ)言,要執(zhí)行BASIC程序,就得進(jìn)入BASIC環(huán)境,然后才能加載程序源文件、運(yùn)行。解釋型程序中,由于程序總是以源代碼的形式出現(xiàn),因此只要有相應(yīng)的解釋器,移植幾乎不成問題。編譯型程序雖然源代碼也可以移植,但前提是必須針對(duì)不同的系統(tǒng)分別進(jìn)行編譯,對(duì)于復(fù)雜的工程來(lái)說,的確是一件不小的時(shí)間消耗,況且很可能一些細(xì)節(jié)的地方還是要修改源代碼。而且,解釋型程序省卻了編譯的步驟,修改調(diào)試也非常方便,編輯完畢之后即可立即運(yùn)行,不必像編譯型程序一樣每次進(jìn)行小小改動(dòng)都要耐心等待漫長(zhǎng)的Compiling…Linking…這樣的編譯鏈接過程。不過凡事有利有弊,由于解釋型程序是將編譯的過程放到執(zhí)行過程中,這就決定了解釋型程序注定要比編譯型慢上一大截,像幾百倍的速度差距也是不足為奇的。
編譯型與解釋型,兩者各有利弊。前者由于程序執(zhí)行速度快,同等條件下對(duì)系統(tǒng)要求較低,因此像開發(fā)操作系統(tǒng)、大型應(yīng)用程序、數(shù)據(jù)庫(kù)系統(tǒng)等時(shí)都采用它,像C/C++、Pascal/Object Pascal(Delphi)、VB等基本都可視為編譯語(yǔ)言,而一些網(wǎng)頁(yè)腳本、服務(wù)器腳本及輔助開發(fā)接口這樣的對(duì)速度要求不高、對(duì)不同系統(tǒng)平臺(tái)間的兼容性有一定要求的程序則通常使用解釋性語(yǔ)言,如Java、JavaScript、VBScript、Perl、Python等等。
但既然編譯型與解釋型各有優(yōu)缺點(diǎn)又相互對(duì)立,所以一批新興的語(yǔ)言都有把兩者折衷起來(lái)的趨勢(shì),例如Java語(yǔ)言雖然比較接近解釋型語(yǔ)言的特征,但在執(zhí)行之前已經(jīng)預(yù)先進(jìn)行一次預(yù)編譯,生成的代碼是介于機(jī)器碼和Java源代碼之間的中介代碼,運(yùn)行的時(shí)候則由JVM(Java的虛擬機(jī)平臺(tái),可視為解釋器)解釋執(zhí)行。它既保留了源代碼的高抽象、可移植的特點(diǎn),又已經(jīng)完成了對(duì)源代碼的大部分預(yù)編譯工作,所以執(zhí)行起來(lái)比“純解釋型”程序要快許多。而像VB6(或者以前版本)、C#這樣的語(yǔ)言,雖然表面上看生成的是.exe可執(zhí)行程序文件,但VB6編譯之后實(shí)際生成的也是一種中介碼,只不過編譯器在前面安插了一段自動(dòng)調(diào)用某個(gè)外部解釋器的代碼(該解釋程序獨(dú)立于用戶編寫的程序,存放于系統(tǒng)的某個(gè)DLL文件中,所有以VB6編譯生成的可執(zhí)行程序都要用到它),以解釋執(zhí)行實(shí)際的程序體。C#(以及其它.net的語(yǔ)言編譯器)則是生成.net目標(biāo)代碼,實(shí)際執(zhí)行時(shí)則由.net解釋系統(tǒng)(就像JVM一樣,也是一個(gè)虛擬機(jī)平臺(tái))進(jìn)行執(zhí)行。當(dāng)然.net目標(biāo)代碼已經(jīng)相當(dāng)“低級(jí)”,比較接近機(jī)器語(yǔ)言了,所以仍將其視為編譯語(yǔ)言,而且其可移植程度也沒有Java號(hào)稱的這么強(qiáng)大,Java號(hào)稱是“一次編譯,到處執(zhí)行”,而.net則是“一次編碼,到處編譯”。呵呵,當(dāng)然這些都是題外話了。總之,隨著設(shè)計(jì)技術(shù)與硬件的不斷發(fā)展,編譯型與解釋型兩種方式的界限正在不斷變得模糊。
動(dòng)態(tài)語(yǔ)言和靜態(tài)語(yǔ)言
通常我們所說的動(dòng)態(tài)語(yǔ)言、靜態(tài)語(yǔ)言是指動(dòng)態(tài)類型語(yǔ)言和靜態(tài)類型語(yǔ)言。
(1)動(dòng)態(tài)類型語(yǔ)言:動(dòng)態(tài)類型語(yǔ)言是指在運(yùn)行期間才去做數(shù)據(jù)類型檢查的語(yǔ)言,也就是說,在用動(dòng)態(tài)類型的語(yǔ)言編程時(shí),永遠(yuǎn)也不用給任何變量指定數(shù)據(jù)類型,該語(yǔ)言會(huì)在你第一次賦值給變量時(shí),在內(nèi)部將數(shù)據(jù)類型記錄下來(lái)。Python和Ruby就是一種典型的動(dòng)態(tài)類型語(yǔ)言,其他的各種腳本語(yǔ)言如VBScript也多少屬于動(dòng)態(tài)類型語(yǔ)言。
(2)靜態(tài)類型語(yǔ)言:靜態(tài)類型語(yǔ)言與動(dòng)態(tài)類型語(yǔ)言剛好相反,它的數(shù)據(jù)類型是在編譯其間檢查的,也就是說在寫程序時(shí)要聲明所有變量的數(shù)據(jù)類型,C/C++是靜態(tài)類型語(yǔ)言的典型代表,其他的靜態(tài)類型語(yǔ)言還有C#、JAVA等。
對(duì)于動(dòng)態(tài)語(yǔ)言與靜態(tài)語(yǔ)言的區(qū)分,套用一句流行的話就是:Static typing when possible, dynamictyping when needed。
強(qiáng)類型定義語(yǔ)言和弱類型定義語(yǔ)言
(1)強(qiáng)類型定義語(yǔ)言:強(qiáng)制數(shù)據(jù)類型定義的語(yǔ)言。也就是說,一旦一個(gè)變量被指定了某個(gè)數(shù)據(jù)類型,如果不經(jīng)過強(qiáng)制轉(zhuǎn)換,那么它就永遠(yuǎn)是這個(gè)數(shù)據(jù)類型了。舉個(gè)例子:如果你定義了一個(gè)整型變量a,那么程序根本不可能將a當(dāng)作字符串類型處理。強(qiáng)類型定義語(yǔ)言是類型安全的語(yǔ)言。
(2)弱類型定義語(yǔ)言:數(shù)據(jù)類型可以被忽略的語(yǔ)言。它與強(qiáng)類型定義語(yǔ)言相反, 一個(gè)變量可以賦不同數(shù)據(jù)類型的值。
強(qiáng)類型定義語(yǔ)言在速度上可能略遜色于弱類型定義語(yǔ)言,但是強(qiáng)類型定義語(yǔ)言帶來(lái)的嚴(yán)謹(jǐn)性能夠有效的避免許多錯(cuò)誤。另外,“這門語(yǔ)言是不是動(dòng)態(tài)語(yǔ)言”與“這門語(yǔ)言是否類型安全”之間是完全沒有聯(lián)系的!
例如:Python是動(dòng)態(tài)語(yǔ)言,是強(qiáng)類型定義語(yǔ)言(類型安全的語(yǔ)言); VBScript是動(dòng)態(tài)語(yǔ)言,是弱類型定義語(yǔ)言(類型不安全的語(yǔ)言);JAVA是靜態(tài)語(yǔ)言,是強(qiáng)類型定義語(yǔ)言(類型安全的語(yǔ)言)。
靜態(tài)類型定義語(yǔ)言
一種在編譯時(shí),數(shù)據(jù)類型是固定的語(yǔ)言。大多數(shù)靜態(tài)類型定義語(yǔ)言強(qiáng)制這一點(diǎn),它要求你在使用所有變量之前要聲明它們的數(shù)據(jù)類型。Java和C是靜態(tài)類型定義語(yǔ)言。
動(dòng)態(tài)類型定義語(yǔ)言
一種在執(zhí)行期間才去發(fā)現(xiàn)數(shù)據(jù)類型的語(yǔ)言,與靜態(tài)類型定義相反。VBScript和Python是動(dòng)態(tài)類型定義的,因?yàn)樗鼈兪窃诘谝淮谓o一個(gè)變量賦值的時(shí)候找出它的類型的。
強(qiáng)類型定義語(yǔ)言
一種總是強(qiáng)制類型定義的語(yǔ)言。Java和Python是強(qiáng)制類型定義的。如果你有一個(gè)整數(shù),如果不顯示地進(jìn)行轉(zhuǎn)換,你不能將其視為一個(gè)字符串。
弱類型定義語(yǔ)言
一種類型可以被忽略的語(yǔ)言,與強(qiáng)類型定義相反。VBScript是弱類型定義的。在VBScript中,可以將字符串‘12’和整數(shù)3進(jìn)行連接得到字符串‘123’,然后可以把它看成整數(shù)123,而不需要顯示轉(zhuǎn)換。但其實(shí)它們的類型沒有改變,VB只是在判斷出一個(gè)表達(dá)式含有不同類型的變量之后,自動(dòng)在這些變量前加了一個(gè)clong()或(int)()這樣的轉(zhuǎn)換函數(shù)而已。能做到這一點(diǎn)其實(shí)是歸功于VB的編譯器的智能化而已,這并非是VB語(yǔ)言本身的長(zhǎng)處或短處。
結(jié)論:
靜態(tài)是類型編譯時(shí)判斷;動(dòng)態(tài)是類型運(yùn)行時(shí)判斷;強(qiáng)類型是類型獨(dú)立,不輕易轉(zhuǎn)化;弱類型是類型不嚴(yán)格區(qū)分,一般是只要大小放得下,就可以轉(zhuǎn)化。這種是匯編級(jí)的觀點(diǎn)。面向?qū)ο蟮挠^點(diǎn)并非這樣的,對(duì)象并不是大小差不多就是類型兼容,而是關(guān)鍵的接口要相同才叫類型兼容。
動(dòng)態(tài)語(yǔ)言并非是弱類型,這是不等價(jià)的。恰好的,一般動(dòng)態(tài)語(yǔ)言都是強(qiáng)類型語(yǔ)言,因?yàn)槎际亲裾彰嫦驅(qū)ο蟮挠^點(diǎn)來(lái)設(shè)計(jì)對(duì)象的。
動(dòng)態(tài)語(yǔ)言的劣勢(shì)很明顯,就是缺少開發(fā)環(huán)境,運(yùn)行效率差,當(dāng)然語(yǔ)言設(shè)計(jì)上也不完美(靜態(tài)語(yǔ)言何止千萬(wàn),但c++也就一個(gè))。
優(yōu)勢(shì)也很明顯,就是編寫容易,層次高,接近自然語(yǔ)義。動(dòng)態(tài)類型語(yǔ)言效率低下的原因,不在于變量的類型是動(dòng)態(tài)的,而在于對(duì)象的方法是動(dòng)態(tài)聯(lián)編的,在這一點(diǎn)上動(dòng)態(tài)類型語(yǔ)言和Java沒什么不同。
靜態(tài)類型語(yǔ)言的優(yōu)勢(shì)究竟是什么?
觀點(diǎn)一:靜態(tài)類型語(yǔ)言因?yàn)轭愋蛷?qiáng)制聲明,所以IDE可以做到很好的代碼感知能力,因?yàn)橛蠭DE的撐腰,所以開發(fā)大型系統(tǒng),復(fù)雜系統(tǒng)比較有保障。
對(duì)于像Java來(lái)說,IDEA/Eclipse確實(shí)在代碼感知能力上面已經(jīng)非常強(qiáng)了,這無(wú)疑能夠增加對(duì)大型系統(tǒng)復(fù)雜系統(tǒng)的掌控能力。但是除了Java擁有這么強(qiáng)的IDE武器之外,似乎其他語(yǔ)言從來(lái)沒有這么強(qiáng)的IDE。C#的VisualStudio在GUI開發(fā)方面和Wizard方面很強(qiáng),但是代碼感知能力上和Eclipse差的不是一點(diǎn)半點(diǎn)。至于VisualC++根本就是一個(gè)編譯器而已,羞于提及Visual這個(gè)字眼。更不要說那么多C/C++開發(fā)人員都是操起vi吭哧吭哧寫了幾十萬(wàn)行代碼呢。特別是像LinuxKernel這種幾百萬(wàn)行代碼,也就是用vi寫出來(lái)的阿,夠復(fù)雜,夠大型,夠長(zhǎng)生命周期的吧。
觀點(diǎn)二:靜態(tài)語(yǔ)言相對(duì)比較封閉的特點(diǎn),使得第三方開發(fā)包對(duì)代碼的侵害性可以降到很低。動(dòng)態(tài)語(yǔ)言在這點(diǎn)上表現(xiàn)的就比較差,我想大家都有過從網(wǎng)上下載某個(gè)JS包,然后放到項(xiàng)目代碼里發(fā)生沖突的經(jīng)歷
也就是說靜態(tài)類型語(yǔ)言可以保障package的命名空間分割,從而避免命名沖突,代碼的良好隔離性。但是這個(gè)觀點(diǎn)也缺乏說服力。
靜態(tài)類型語(yǔ)言中C,VB都缺乏良好的命名空間分割,容易產(chǎn)生沖突,但是并沒有影響他們做出來(lái)的系統(tǒng)就不夠大,不夠復(fù)雜。
而Visual C++開發(fā)的DLL版本沖突也是臭名昭著的,似乎C++的命名空間沒有給它帶來(lái)很大的幫助。
而動(dòng)態(tài)類型語(yǔ)言中Ruby/Python/Perl都有比較好的命名空間,特別是Python和Perl,例如CPAN上面的第三方庫(kù)成噸成噸的,也從來(lái)沒有聽說什么沖突的問題。
誠(chéng)然像PHP,JavaScript這樣缺乏命名空間的動(dòng)態(tài)語(yǔ)言很容易出現(xiàn)問題,但是這似乎是因?yàn)樗麄內(nèi)狈O機(jī)制導(dǎo)致的,而不是因?yàn)樗麄儎?dòng)態(tài)類型導(dǎo)致的吧?
說到大型系統(tǒng),復(fù)雜業(yè)務(wù)邏輯系統(tǒng),Google公司很多東西都是用python開發(fā)的,這也證明了動(dòng)態(tài)類型語(yǔ)言并非不能做大型的復(fù)雜的系統(tǒng)。其實(shí)我個(gè)人認(rèn)為:
動(dòng)態(tài)類型語(yǔ)言,特別是高級(jí)動(dòng)態(tài)類型語(yǔ)言,反而能夠讓人們不需要分心去考慮程序編程問題,而集中精力思考業(yè)務(wù)邏輯實(shí)現(xiàn),即思考過程即實(shí)現(xiàn)過程,用DSL描述問題的過程就是編程的過程,這方面像UnixShell,ruby,SQL,甚至PHP都是相應(yīng)領(lǐng)域當(dāng)之無(wú)愧的DSL語(yǔ)言。而顯然靜態(tài)類型語(yǔ)言基本都不滿足這個(gè)要求。
那靜態(tài)類型語(yǔ)言的優(yōu)勢(shì)究竟是什么呢?我認(rèn)為就是執(zhí)行效率非常高。所以但凡需要關(guān)注執(zhí)行性能的地方就得用靜態(tài)類型語(yǔ)言。其他方面似乎沒有什么特別的優(yōu)勢(shì)。
給你來(lái)個(gè)例子把
弱類型語(yǔ)言vbs:
a=1
b=a+“1”+“a” //結(jié)果是11a,這里 a 成了字符串
c=a+1 //結(jié)果是2 ,這里a則是數(shù)字型
強(qiáng)類型語(yǔ)言:c#
int a=2
string b=a.ToString()+“1”+“a”
int c=a+1
看到了嗎?區(qū)分大小寫,需要實(shí)現(xiàn)申明類型外,一個(gè)重要的區(qū)別是,弱類型的語(yǔ)言的東西沒有明顯的類型,他能隨著環(huán)境的不同,自動(dòng)變換類型
而強(qiáng)類型則沒這樣的規(guī)定,不同類型間的操作有嚴(yán)格定義,只有相同類型的變量才能操作,雖然系統(tǒng)也有一定的默認(rèn)轉(zhuǎn)換,當(dāng)絕沒有弱類型那么隨便
ps:弱類型代碼簡(jiǎn)單,但因?yàn)樽兞繘]有確定的類型,所以容易出錯(cuò)!強(qiáng)類型代碼復(fù)雜(比如:轉(zhuǎn)換日期顯示格式 (convert.toDatetime(“2007-1-1 08:08:08”)).ToString(“yyyy-MM-dd”),呵呵你可以看到這種寫法相當(dāng)麻煩),但因?yàn)橛袊?yán)格定義所以不容易出錯(cuò)
評(píng)論
查看更多