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