JAVA無用論 2000-10-24 1. 寫這篇文章的目的 學(xué)了一些關(guān)于Java的東西,個(gè)人認(rèn)為它很不好用。為了減少上當(dāng)人數(shù) 特寫此文。 盡管 java 宣稱它是100%面向?qū)ο螅鳦++不是。但是宣稱100%面向 對(duì)象本身就不是什么面向?qū)ο蟮乃枷搿C嫦驅(qū)ο蟮谋举|(zhì)目的是提高生 產(chǎn)率。討論一種語言是否100%面向?qū)ο缶秃孟裼懻撐覀兊纳鐣?huì)性資性 社一樣滑稽。其實(shí)學(xué)習(xí)面向?qū)ο蟛灰欢ǚ且褂胘ava不可。我反而認(rèn) 為120%面向?qū)ο蟮腃++是不錯(cuò)的選擇。 Java號(hào)稱跨平臺(tái),其實(shí)這是只一個(gè)夢(mèng)想,也不妨用騙局這個(gè)詞來形容 。軟件的移植性僅僅和虛機(jī)相關(guān)嗎?照此理論是不是可以說符合IA32 體系的軟件在任何IA32體系上都能正常運(yùn)行。那我怎么沒看見SCO: :lf 在 NT上運(yùn)行?顯然,除了虛機(jī),軟件二進(jìn)制規(guī)范(執(zhí)行文件格 式、連接方法)、運(yùn)行時(shí)間庫(kù)和系統(tǒng)調(diào)用也是軟件移植問題因素。而 java規(guī)范中顯然不包括完整的運(yùn)行時(shí)間庫(kù)和系統(tǒng)調(diào)用,甚至二進(jìn)制規(guī) 范也有不兼容的地方(比如本原接口和固有接口)。軟件總不能脫離 它的運(yùn)行環(huán)境,不兼容就從這里開始。 要提高軟件生產(chǎn)效率。應(yīng)當(dāng)認(rèn)認(rèn)真真的研究系統(tǒng)結(jié)構(gòu)、二進(jìn)制規(guī)范、 系統(tǒng)調(diào)用結(jié)構(gòu)才是解決問題的方法。靠概念游戲這種投機(jī)取巧的方法 是行不通的。 我說java不好,甚至不必對(duì)其側(cè)目,你信嗎?我估計(jì)信的人不多。我 只是想說“上當(dāng)之后別怪我沒說”。 另外如果您在Java中發(fā)現(xiàn)了甜頭也不妨告訴我。互相學(xué)習(xí)嗎:)。 2. Java究竟是什么? Java是一種虛擬硬件系統(tǒng)結(jié)構(gòu),是一種軟件二進(jìn)制規(guī)范,是一種編程 語言。當(dāng)我們看到Java一詞時(shí),它可能表達(dá)上述三個(gè)含義鐘的任何一 個(gè)。盡管這三個(gè)東西可以獨(dú)立存在,不過實(shí)際上他們總是在一起出現(xiàn) 。所以也很少有人分的那么明確。使用Fortran語言編寫Java虛機(jī)上 的代碼理論上是可行的。但是有誰樂意做這件事呢? 作為虛擬硬件體系結(jié)構(gòu), Java虛機(jī)和ALPHA、PowerPC、SPARC、IA32、51、960是同一概念上的 東西。也許您會(huì)奇怪?他們?cè)跏峭瑯拥臇|西呢?IA32不就是PIII、PI V那一大塊嗎?其實(shí)不然、我們知道386、P5、P6、P7的內(nèi)部結(jié)構(gòu)非常 不同。屬不同的微體系。但是他們實(shí)現(xiàn)了相同的IA32指令集合。IA32 也不一定非要通過硬件實(shí)現(xiàn),通過軟件也可以。這種軟件CPU產(chǎn)品廣 泛出現(xiàn)在操作系統(tǒng)和CPU密集軟件的開發(fā)、調(diào)試工具上。主要用于在C PU出現(xiàn)之前調(diào)試軟件。Java指令集同樣也可以通過硬件實(shí)現(xiàn)。只是在 半導(dǎo)體工業(yè)激烈競(jìng)爭(zhēng)的時(shí)代,沒有大公司(含SUN)愿意把這么做。 SUN常常說M$很害怕java。他們之間的確存在很強(qiáng)的競(jìng)爭(zhēng)關(guān)系。倒不 是Java高級(jí)語言的問題,我認(rèn)為是Java二進(jìn)制規(guī)范和 Windows操作系 統(tǒng)存在競(jìng)爭(zhēng)。不妨考察Java中的(.class文件格式、裝入方法、執(zhí)行 過程、JDBC接口、J3D接口)和Windows中的(PE文件格式、DLL文件格 式、裝入、連接方法、ODBC、Direct3D)。就知道競(jìng)爭(zhēng)多么強(qiáng)烈。和N T/IA不同。Java.exe執(zhí)行程序包含虛機(jī)規(guī)范和二進(jìn)制規(guī)范。在NT/IA 中是分離的產(chǎn)品。 人們總喜歡把Java高級(jí)語言和C++類比,他們之間的確存在很過相似 的地方。不過我認(rèn)為C++和Java不存在什么競(jìng)爭(zhēng)。它們使用在不同的 場(chǎng)合。他們的區(qū)別(內(nèi)存管理、對(duì)象類型、線程規(guī)范)決定他們的用 途。用形似而神不似來形容C++和Java吧。僅從高級(jí)語言方面來看。J ava真正競(jìng)爭(zhēng)來自ECMAScript 。也就是JScript和VBScript。 3. Java虛機(jī)和IA32比較 Java VM和IA32最大的區(qū)別是Java VM的主要實(shí)現(xiàn)不考慮效率問題。由 此派生出寄存器少,指令結(jié)構(gòu)簡(jiǎn)單(同樣功能生成的程序代碼長(zhǎng)), 尋址空間小,尋址方法少、數(shù)據(jù)類型少等。除了上述問題,Java VM 沒有涉及指令(顯式或隱式)并行問題。 3.1. 基本特性差別 3.1.1. 數(shù)據(jù)類型比較
Java VM IA32 整數(shù)類型 byte short(16bit) char(UnionCode) int long (64bit) {不存在無符號(hào)算術(shù)運(yùn)算指令,另外注意這里沒有boolean類型} byte Word(16bit) DoubleWord(32bit) QuotaWord(64bit) DoubleQuotaWord(2*64bit) BCD/PackedBCD BitField {存在有符號(hào)和無符號(hào)兩種運(yùn)算指令} 浮點(diǎn)類型 float(32bit) double(64bit) float(32bit) double(64bit) long double(80bit) Packed double(2*64bit) 地址 returnAddress* 8bit , 16bit , 32bit , 48bit都有
沒有顯示的看到returnAddress 類型的寬度,不過。通過指令goto(0xa7)和goto_w(0xc8)來看。retu rnAddress是可以是16位或32位的。 關(guān)于double和Long的原子問題:在目前的java規(guī)范中,double和long 作為兩個(gè)獨(dú)立的32 位數(shù)據(jù)獨(dú)立存取。這樣可能產(chǎn)生同步問題。歷史 上Intel的CMPXCHG8B(Pentum pro以上CPU提供)指令就存在過類似 問題,一度被指責(zé)是CPU設(shè)計(jì)問題。好在CMPXCHG8B很少使用,沒有造 成什么事故。 3.1.2. 指令集 指令類型 JavaVM IA32 Load/Store 1) 數(shù)據(jù)和運(yùn)算棧之間單個(gè)移動(dòng) 2) 常數(shù)移入運(yùn)算棧
1) MOVE 2) CMOVEXX 3) 交換,瑣操作 4) PUSH/POP 5) PUSHA/POPA 6) IN/OUT 元算指令 add , sub , mul , div , neg , rem , shl , or , and , xor 比Java多多了,主要多在顯式并行上 類型轉(zhuǎn)換 基本類型之間可以互相轉(zhuǎn)換 有(由于類型很多,轉(zhuǎn)換指令也有很多) 方法調(diào)用 4條指令 一大堆,主要多在權(quán)限切換(調(diào)用門)、長(zhǎng)短跳傳不同上。
3.1.3. 異常 雖然JavaVM有異常的支持,不過很簡(jiǎn)單。它不區(qū)分中斷、陷阱和故障 。也不能明確指出出錯(cuò)代碼的PC,并返回那里重新執(zhí)行。 3.1.4. 執(zhí)行態(tài) Java VM沒有用戶態(tài)和系統(tǒng)態(tài)執(zhí)行區(qū)分。當(dāng)然也沒有MMU(管理內(nèi)存分 頁(yè)、分段的內(nèi)存管理單元).除非被Java高級(jí)語言限制,java VM匯編 代碼也能完成一些惡意操作。 3.1.5. 小結(jié) 總而言之,Java VM很簡(jiǎn)單。SUN總是認(rèn)為通過編譯優(yōu)化Java可以達(dá)到 C++速度。顯然是謊言。如果要編譯成本地代碼,顯然要丟失移植性 。如果不編譯成本地代碼,效率問題如何解決?有一種及時(shí)編譯的設(shè) 計(jì)。對(duì)于很小的應(yīng)用也許可行。對(duì)于規(guī)模的應(yīng)用呢?要知道優(yōu)化編譯 很費(fèi)CPU和內(nèi)存。像IA64體系的優(yōu)化方案,要編譯很多遍才能優(yōu)化完 成。要運(yùn)行時(shí)刻編譯是不是天方夜譚。 4. Java高級(jí)語言和C++、JScript比較 4.1. 效率,謊言 很多書上寫Java是很快的語言。這時(shí)一定要看清楚是比誰快。語句傳 了幾本書難免有些誤差,比較對(duì)象經(jīng)常有意無意丟失。一般認(rèn)為Java 比JScript快。的確快很多,不只十倍。我也承認(rèn)Java比JScript快。 但有人說Java和C++效率接近。這就是騙人了。他們也能做出試驗(yàn)證 明,試驗(yàn)結(jié)果好像也能證明結(jié)論。他們的實(shí)驗(yàn)大概都是形如這樣。
Java, C++測(cè)試代碼: for ( I = 0 ; I<100 ; I++ ) { RemoteCall( I ); //外部調(diào)用,調(diào)用一次用1s。 } 結(jié)果: Java 102s , C++ 100s。 結(jié)論: Java達(dá)到了C++ 98.0%的效率。 這種測(cè)試違背了測(cè)量學(xué)中要把測(cè)試對(duì)象放到主要矛盾上這一基本原 理。方法的不正確當(dāng)然帶來了測(cè)試結(jié)果的不正確。有本事比比 for ( I = 0 ; I<10000; I++) { y = x * z; //由Java語言或C++語言實(shí)現(xiàn)執(zhí)行體 } 我的結(jié)果是170倍。也就是PIII變成了286。如果使用指令并行優(yōu)化 ,C++和Java的速度差異可以達(dá)到千倍以上。想用一下8088嗎? 4.2. 功能缺失導(dǎo)致代碼膨脹 簡(jiǎn)單的說,Java比C++缺少編譯預(yù)處理、缺少運(yùn)算符重載、多繼承和 類模板。我認(rèn)為取消這些概念很粗暴。和C++不同。對(duì)于大規(guī)模編程 來說,Java的代碼量不會(huì)比C少多少。甚至由于類型約束太強(qiáng)。有可 能比C的代碼量還大。 Java常稱多繼承比較困難,所以要取消。而且使用實(shí)現(xiàn)接口的方法可 以代替C++的多繼承。但是,實(shí)現(xiàn)接口要自己寫所有的接口實(shí)現(xiàn)代碼 。不嫌煩就慢慢寫吧。 為什么要取消運(yùn)算符重載?真是不可理解,既簡(jiǎn)單又好用。它居然說 難,且容易造成混亂。 總之,處理這幾個(gè)大方向的問題,還有很多小問題。據(jù)說AWT不好用, 感覺他們?yōu)榱送瓿扇蝿?wù)寫程序。 4.3. 簡(jiǎn)單的騙局 自古便宜沒好貨。Java總是宣揚(yáng)Java如何簡(jiǎn)單,主要宣揚(yáng)的好處是垃 圾自動(dòng)收集和線程同步。其實(shí)不然,由于Java沒有釋放關(guān)鍵字。使得 不能及時(shí)釋放或定時(shí)釋放不必的數(shù)據(jù)。要知道能夠分配的不只是內(nèi)存 ,還有數(shù)據(jù)庫(kù)句柄、文件句柄、結(jié)果集等。這樣不得不繞來繞去的完 成這些任務(wù)。其實(shí)C++的析構(gòu)函數(shù)是自動(dòng)調(diào)用的,也不用自己手動(dòng)掉 用。遇到一些特殊情況,C++也能很好的解決。 也許java的線程比較簡(jiǎn)單吧,不過C++中也可以繼承線程類。由于本 人沒有涉及線程編程。這里不好亂說。 5. Java的兼容性 相對(duì)本地代碼來說,Java程序的確移植性比較好。歸其原因不外有二 。一來Java虛機(jī)只一種(不像天下有很多種CPU),二來Java二進(jìn)制 規(guī)范只有一種(不像這么多種操作系統(tǒng))。但是,Java代碼真的可以隨 心所欲的移植嗎?其實(shí)不然,上述兩條中的任何一種不再滿足,都會(huì) 影響B(tài)yteCode的移植性。 現(xiàn)在,Java的主要版本已經(jīng)有1.0 , 1.1.7 , 1.2(2.0)三個(gè)。更殘酷 的是1.1.7和1.2不兼容。一個(gè)很著名的例子。Websphere不能在Java1 .2上運(yùn)行。另外WebLogic不能在1.0上運(yùn)行。 java的二進(jìn)制規(guī)范呢?jview( MS java)就自立門戶。他的.class裝 入方法就和java for win32不同。另外它提出了其他的本地代碼連接 方法。顯然這里也會(huì)造成不兼容。 除了上述兩條重要的原因,還有就是程序的運(yùn)行環(huán)境。比如操作系統(tǒng) 是否區(qū)分文件名的大小寫。數(shù)據(jù)庫(kù)是否中調(diào)用都能返回執(zhí)行成功。EJ B的代碼是否有EJB 的運(yùn)行服務(wù)器。等等。 6. 在精通Java之前否定Java 本人只是對(duì)Java略知一二。為什么就非要否定java呢。其實(shí),從一般 科學(xué)觀點(diǎn)審視java。就會(huì)發(fā)現(xiàn)其中的問題。 6.1. Java代碼不符合從簡(jiǎn)單到復(fù)雜的認(rèn)識(shí)規(guī)律 代碼比較: Java Code Example: import java.applet.*; import java.awt.Gaphics; public class HelloWorldApplet extends java.applet.Appple { public void init(){ resize( 200 , 150 ); } public void paint( Graphics g){ g.drawString("Hello World" , 50 , 100); } }
C++ Code Example: #include class Hello :public Applet { public void init(); public void paint(Graphics g); };
Hello::init() { resize( 200 , 150 ); } ......
我們看到,java開始就要求寫函數(shù)的實(shí)現(xiàn)。而C++先要描述輪廓。再 寫函數(shù)實(shí)現(xiàn)。 6.2. Java對(duì)從一般到特殊的思維方法支持的不好 從一般到特殊,是重要的思維方法。對(duì)應(yīng)到計(jì)算機(jī)學(xué)科就是繼承。而 今多繼承的概念已經(jīng)廣為流傳。比如我們說“小花貓”,就是繼承“ 小”、“花”、“貓”三個(gè)概念。如果在字典上看到小花貓這個(gè)詞, 它一定不再描述“小”、“花”、“貓”這三個(gè)概念,而是繼承他們 。但是java只能繼承其中的一個(gè)。對(duì)另外連個(gè)還要仔細(xì)的描述。寫起 來是不是很煩。 6.3. Java設(shè)計(jì)不尊重“任何事物都有產(chǎn)生、發(fā)展、消亡的過程”這 一自然規(guī)律 Java沒有析構(gòu)函數(shù)。這一點(diǎn)很討厭。我只想重復(fù)一遍“對(duì)象不都在內(nèi) 存空間中”。 6.4. Java 不能表達(dá)少數(shù)類之間的緊密相關(guān) java要求每個(gè)類使用一個(gè)文件。這種實(shí)現(xiàn)可能和它的自動(dòng)編譯執(zhí)行方 式有關(guān)。注意這種限制不是實(shí)現(xiàn)上問題,而是規(guī)范中的語句。但是這 種方法合適嗎?請(qǐng)看下面C++的例子。將這兩個(gè)類分開為兩個(gè)文件是 否真的好讀? struct menuitem{ String strX; int iIndex; };
class menu{ menuitem item[100]; ... ... }; 和這種情況類似,javadoc也不能對(duì)緊密相關(guān)的數(shù)據(jù)進(jìn)行描述。 至于類模板。java更是不支持。自己一個(gè)一個(gè)的慢慢寫吧。 6.5. 批判Java的批判 Java要誕生,必須批判原有C/C++語言的缺陷。列舉其中一二。 “C/C++語言中的整形數(shù)據(jù)不限制長(zhǎng)度。這樣一來當(dāng)程序從32位系統(tǒng) 移植到16 位系統(tǒng)時(shí)會(huì)造成錯(cuò)誤”。可是仔細(xì)想想。這種移植的概率 究竟有多少? “Java不像C/C++,它完全不支持指針”。按此理論,同樣不支持指 針的Fortran77和basic是不是也很強(qiáng)壯。 “Java不允許隱式類型轉(zhuǎn)換”。如果整形和浮點(diǎn)數(shù)據(jù)之間的轉(zhuǎn)換都要 寫一下,是不是很煩。 “聯(lián)合體、全局變量他們都不是面向?qū)ο蟮臇|西”。面向?qū)ο笠恢本? 沒有什么定義。本著好用的東西就是好東西的原則,保留這些概念也 不錯(cuò)。像M_PI這類的常量或者項(xiàng)目中的確全局相關(guān)的準(zhǔn)常量,使用全 局變量是不是很方便?至于聯(lián)合體,是優(yōu)化存儲(chǔ)效率用的,像 Java 這種不考慮效率的語言自然不會(huì)支持。 “java存在比C++多的運(yùn)算符”。好像是多一些,他們是(字符串 +), > >> , (boolean)& and | , instanceof。但是我們分析一下。由 于java不支持運(yùn)算符重載,只好單獨(dú)實(shí)現(xiàn)(字符串 +)。由于java 不 區(qū)分有符號(hào)和無符號(hào)數(shù)據(jù),所以使用>>>來表達(dá)無符號(hào)右移、由于jav a中的boolean和整形之間沒有聯(lián)系,又不支持運(yùn)算符重載,所以對(duì)bo olean類型單獨(dú)實(shí)現(xiàn)& and |。至于instanceof的確是Java 獨(dú)創(chuàng),不 過這個(gè)運(yùn)算符的用處還要考慮。我在引用某變量時(shí)居然能不知道它的 類型?
6.6. 兼容以不兼容為代價(jià) 使用java 必須一切從頭開始。java不能繼承原有的工作。而且它也 不能很好的和其他語言混合編程。這就和C++區(qū)別大了。首先C++繼承 了大部分C語言代碼。其次,C++可以和Pascal , Fortran , Basic, T-SQL等其他語言方便混合。尤其方便的是ASM語言和 C++混合。發(fā)揮 不同語言的長(zhǎng)處。俗話說“朋友多,天地寬”嗎。而 java只能孤軍 奮戰(zhàn)了。 7. 結(jié)束語 寫這篇文章用了一天半的時(shí)間。又在Java上花了這么多時(shí)間,真是心 痛。但愿有些效果。
7/7
|