.NET系列 第一篇 關於跨平臺的種種言論之我見

directray發表於2010-12-11

說到.NET,就不能不提到跨平臺這個很詭異的事實。.NET的跨平臺和Java的跨平臺說像也像,說不像呢,也不像。看起來都是在一堆庫上面跑的程式碼,都是某種意義上的託管程式碼,但是實際上還是不一樣的。

首先是能夠用於開發的語言。.NET的VM制定了一系列的標準,為位元組碼做出了很多規範,並且提交成為ECMA國際標準。所有的語言都可以加入進來,只要你可以支援最低要求的CLR標準CTS,也可以生成IL位元組碼,如此便可。JVM其實也差不多,只要你的編譯後的檔案符合Java的位元組碼要求就行。

但是這裡面其實是有一個比較大的不同點的。.NET提倡一個互操作的概念。也就是說,只要你是正式加入到.NET家庭裡來的語言,都可以協同工作。比如你用COBOL.NET做一點數字計算的庫,然後介面封裝成CLR型別,就可以被C#等支援此型別的語言呼叫。簡單舉個例子,在CLR裡面有個標準的字串型別叫做String。而C#自身還有個字串型別,叫做string。如果檢視型別定義會發現,其實二者差異並不大。但是有個很關鍵的問題在於,string不是CTS成員而String是。所以只要是返回String的庫,C#都可以用。其他的以此類推。

但是JVM在這個方面不是很提倡,所有的程式碼必須符合統一的規定,是屬於全是全非的概念。最典型的例子在於,Groovy的介紹裡說,可以編譯成為JVM可以識別的位元組碼。這個意思就是說,Groovy支援JVM的標準。但是如果要自己有擴充,就會是一個比較麻煩的問題。同時,Java主要的庫格式是jar,也就是一個包含特殊檔案結構的zip檔案。這種鬆散自由的檔案格式也造成了JVM某種程度上的阻滯。換言之,所謂的jar不過是對一堆一堆的class檔案進行壓縮並規定或不規定入口點,僅此而已。

那麼二者的不同點在哪裡?最主要的一個問題,就是參與進來的語言的多寡。而造成語言多寡的一個最重要的原因,還是出在VM上。由於CLR允許一個編譯器只支援一部分的標準,也就是你支援的標準集合是CTS的超集就可以,至於多出多少,那是後話,再議。而JVM的話,貌似沒有這個講法。這就給實現造成了很大程度上的不便。眾所周知,Java是單繼承多介面的一種語言,而很多語言支援多繼承。其次,有的語言不支援OOP,有的不支援無符號數,各式各樣的情況非常複雜。最簡單的一點,如果想生成一個在JVM上跑的C++,估計會非常之困難。因為一個是單根繼承,一個是多繼承。

其次就是託管的力度上有差異。JVM在託管這個問題上依然是全是全非的做法。也就是說,你要麼都是託管程式碼,跑在我JVM上,要麼您就自己個玩去吧。而我相信做個C#開發的童鞋們應該見過一個Attribute,叫做DllImport,這個東西就是用來引入非託管程式碼的。一般來說,是在CTS實現的COM基礎上進行互操作。雖然不建議這麼玩,呵呵。Java裡面也有類似的東西,叫做JNI。但是實際而言,用到JNI的機率不是很大,因為JNI呼叫的是系統相關的程式碼。

也許會有人問,DllImport和JNI都是呼叫系統庫,都是去找系統相關的東西,這不就是一樣一樣的麼。其實不然。

從微軟的戰略角度來說,他的想法當然是統一全宇宙大家都用我的Windows,這是很自然的事情。而在Windows平臺上,第三方庫的基本形式就是DLL檔案,這檔案其實是一個內嵌自描述清單的PE32檔案。換言之,給它個Main函式,人家就自己個跑起來了。和EXE的唯一差別也就是木有入口點,就是一堆函式而已。在目前可以考察到的平臺上,還有一種格式,就是so。也就是*nix平臺。這種格式我沒有做過深入研究,不過既然能實現和DLL類似的功能,那麼自然也是有自描述清單一類的東西嵌在檔案裡。估計微軟不管是放任MONO做大還是自己搞個虛擬機器,都會根據這個情況來修改DllImport。

而JNI在某種程度上來說,由於Java的戰略目標是徹底踢開OS,自己成為一個小的OS,所以難免在和系統底層互動的時候出現一些問題,或者說一些難題。這也是Java裡有很多類似System開頭的常量的原因所在,為了相容每個系統的不同,不得不如此。最簡單的例子,換行符。從ASCII角度來說,有的是10,有的是13,有的是10 13。我之前看過Mina的原始碼,在狀態機裡有一段switch case。這段程式碼裡羅列了windows,unix,mac以後,寫了個default,也就是說預設情況。這其實是一種很不妥當的策略。也許,假設,某一天BEOS又重新恢復了活力,人家的換行符和您的不一樣,您咋弄?這裡雖然不是說批判mina這個優秀的Apache框架,但是這也是一個小小的問題。

說了這麼多,總結一下吧。究竟.NET和Java的跨平臺實現有什麼不同呢?

其實兩者在技術上相差無幾,而且.NET實際上是在Java的基礎上發展起來的。區別主要在於對待跨平臺的實現方針上。.NET系列主要是紮根於每個不同的作業系統,做出不同的執行環境,所以可以實現一些特有的功能,而自己的程式設計師不用去考慮10 13之類的問題。而Java主要是方針是在作業系統上架起一層環境,剝離開每個系統的不同,實現一個大同世界,力圖用自己的虛擬機器來完全模擬作業系統。只是因為世界本不平,所以Java會出現不能Run Anywhere的局面。類似10 13之類的問題,還有其他很多很多的問題,導致了Java出現Write Once,Debug Anywhere的局面。

不能說Java不好,也不能說.NET一定優秀,孰優孰劣,交給時間去定奪吧。下次準備和大家談談關於.NET和Java在對待自己的程式設計師方面的一些不同。

相關文章