Java 的可移植性 (轉)

worldblog發表於2007-12-04
Java 的可移植性 (轉)[@more@]

這是一位MS工程師寫的一篇文章,應該說對的態度是比較客觀的,歡迎大家看完之後發表意見

Java 的可移植性

Michael Edwards
公司開發技術工程師

序言:namespace prefix = o ns = "urn:schemas--com::office" />

我一直都懷疑被那些自以為博學的人不停討論的最熱門的話題Java™ 。您可以用一分為二的觀點來對待這些問題,最終你被迫相信 Java 將帶來世界和平並能償還美國的國債或者它完全是在浪費時間。我常常想涉足這些討論,但我還是儘量避而不談,直到我能夠提供廣博的觀點。

設想一下當我從聖誕節假期歸來時發現我的下一個任務是需要學習 Java 時,我是多麼的驚慌(或者應當說成是恐懼)。你能說“留心你想要得到的東西,因為你可能正在得到它”嗎?但是,我很高興的發現學習比我預計的要容易。Java 是面向的設計方法,作為一個長期在複雜凌亂的 C++ 世界掙扎的 C 員,經過多年的物件導向的,作為一種回報我發現確實學到了一些原理和技術。的確,我承認我是一個 OLE 熱衷者(閱讀過 Nigel Tompson 的系列文章的 MSDN 訂閱者都會理解我的意思),至少在產品程式碼遷移方面如此。但是,漸漸的我離開了無序的行列,至少在考慮 Java 時是這樣。

我的第一個決定——並且是一個正確的決定——避免了選擇類似於《利用你五天刷牙的時間學會 Java》這樣的書。如果你最近到過書店的技術部分(如果你可以外出),會知道那裡有許多 Java 書籍。為了縮小你的查詢範圍,你可以選擇適合自己的書。因為我有豐富的 C 程式,我找到一些適用於 C 程式設計師學習 Java 的書。例如,找到一本David Flanagan 所著的《簡單的Java》(Java in a Nut 專用參考 1996年12月。ISBN:1556592183)。我還買了一本Addison-Wesley 出的《Java 系列》(參見),這些書的確十分有用,但大部分都是程式設計參考。按照我自己透過實踐進行學習的習慣,沒過多久我就熟悉了。我開始時編寫示例 Applet 程式,這在當時看來是很有用的,但很快我就認識到自己的知識很有限需要深入的學習。於是我開始瀏覽微軟的 站點和 站點, 並且在下列站點也找到一些資料(這不是一個全面的列表):

·  Java 開發者 (最好的Java 程式設計疑問與解答)

·  “Java Jolt”  (Web Developer.的指導專欄週刊)

·  “”  (Java 列表摘要週刊和Mentor Software Solutions 的新聞組活動)

·    (每月的關於 Java 社團的IDG 雜誌)

·    (每月更新的 Java 新聞和線上見解e-zine)

權威人士一些關於 Java 的觀點讓我感到鼓舞,我又回到原先起步階段的 Applet 示例中,但是很快就又轉移了視線,開始閱讀 Sun Java 開發工具()的 Applet 示例源程式——可以從http://www.javasoft.com/nav/developer/index.html 。自然,當我開始看實現系統類的時,覺得閱讀示例源程式更有趣。

我的 Java 學習方法實踐證明是比較成功的。由於正確的選擇了適合自己 C 程式設計背景的啟蒙書籍,我對 Java 有了相當充分深入的理解。學習的第二階段透過到 Web 站點瀏覽,我又掌握了關於 Java 開發工具和相關問題的最新資訊。經過閱讀原始碼,使我對 Java 的結構和實現有了本質的認識。

關於 Java 系列文章的第一篇將幫助每個 C 程式設計師解答“Java 可移植性的關鍵是什麼?”這個問題。我將重點介紹設計方面使 Java 應用程式比其他技術在不同計算機平臺之間有更好的可移植性的原因。但是,如果你想徹底理解這一切,Java 良好的可移植性內部的理論將是你學習的一個重點。我看到在 Java 新聞組中有大量的佈告,反映出實際使用時不斷出現的真正的問題。當然,人們也在抱怨 Java 的相容性問題,我將從根本上解釋這一問題。如果你認為該主題的文章有幫助,我將很感激你能告訴我(我的 e- 地址是michaele@microsoft.com )。

關於可移植性

提供建立高可移植性應用程式的便利是 Java 設計體系的核心要素。我的大部分程式設計經驗是關於 C 語言的,八十年代當我開始自己的計算機遊戲程式設計師生涯時,我就開始與可移植程式碼問題朝夕相伴。我所在的遊戲公司常期支援幾個不同的平臺,包括Apple II、C64、Mac、Amiga、Atari ST 和 PC——使用遊戲控制檯,但未能成功。因此,“移植儀定”彷彿成了我的名字。當我在這些平臺之間移植遊戲時我學到了重要的一課:不存在完全可移植的程式碼;僅僅是可移植程式碼多和少的問題。我同時也掌握了一個可以產生儘可能多的可移植程式碼的方法。對我們來講,這個方法包括儘可能多的用 C 語言編寫程式碼,使用我們稱為虛擬機器的技術——我們移植到不同平臺時所使用的基本庫程式碼,該庫充當執行我們的遊戲程式所需的虛擬圖形和輸入庫。因此,從我個人來之不易的建立可移植經驗,我能證實 Java 通常使用可靠性好的技術來生成高可移植性的程式碼更容易。

總體上講,我認為虛擬機器方法將所有不同的平臺平等對待來自一定的協定。為了解釋這一點,讓我講述一個關於我所作的一個工程的故事,這是在我退出開發計算機遊戲之前的最後一個工程。1988年,我所在的遊戲公司面臨一個艱難的決定,是否放下 Amiga 和Atari ST 對我們 PC 遊戲的支援。那時我年輕而又天真,這個問題激怒了我。我們既然已經在 Amiga 上取得了初步的成功——我們怎麼能考慮要放棄所建立的最好的遊戲計算機?於是我日夜不停的工作了三個月來將我們的虛擬機器移植到Amiga 和 Atari ST 平臺上,並且我深信我可以將釋出這些版本的問題化簡為簡單的重新編譯問題。自然,我成功的實現了我們虛擬機器的移植,甚至我還用了不到一週的時間演示了一個我們遊戲的Amiga 和 Atari ST 版本。你能猜想到發生了什麼嗎?最終我們還是放棄了該平臺。在1988年擁有 Amiga 的人中沒有願意僅僅為了 PC 遊戲的移植而花錢的。如果他們想擁有一個 PC,他們會買一臺 PC。相反,如果他們想要一個真正的遊戲計算機,他們會買一臺Amiga(這畢竟是1988年)。從中我接受了一個沉重的教訓:虛擬機器迫使你在編寫軟體時要在所需支援的結構上採用儘可能少的非公共標準。如實地支援不同結構中的不同特性需要額外的工作而且並不一定總是一個可行的選擇。

一個簡要的澄清:我的同事程式設計師Paul Johns 審閱這篇文章時,他指出我的不恰當修辭比喻暗示:可移植程式碼與跨平臺程式碼相同。可移植性意味著簡單的重新編譯一下軟體就可以執行在另一個平臺上,而跨平臺(Java 輔助建立的定義)意味著只要編譯一次程式碼就能夠執行在任何地方(或者按照批評者所說的,編譯一次就可以執行在任何它可以執行的地方)。我認為Paul 是正確的跨平臺程式碼與可移植程式碼不同,但是你可以認為跨平臺程式碼是所有可移植程式碼的根源。

是什麼使得 Java 適合各種需求,使我們稱它為跨平臺可移植的呢?有三個主要的原因:結構上提供了原始碼級的可移植性;應用程式程式設計模型被廣泛而精確的描述(特別是作為語言的一個部分本身);語言的幾個要素使它們易於移植。

虛擬機器

我已經反覆讀到Java 是一個解釋型程式語言。但是,這並不是嚴格正確的;更準確的講 Java 語言通常(不總是)編譯成位元組程式碼,而位元組程式碼有時(但不總是)被解釋。因此, Java 原始碼並不直接被翻譯為特定計算機所特有的低階機器指令。但是等一下——當我修補 Java Applet 示例程式時,我用一個從它的原始碼產生一個 Java 類。當我用Microsoft Inte 測試編譯好的Applet 時,我使用Microsoft's Just-In-Time 編譯器來加速Java Applet 的(參見 MSDN 庫中的“Just-In-Time 編譯器的描述”,基本知識文章 Q154580)。

什麼是被編譯,什麼是被解釋?Java 編譯器產生的二進位制指令(被稱為位元組程式碼)是由一組嶄新的虛擬機器本身的低階機器指令組成。用於解釋已編譯Java 位元組程式碼的虛擬機器作為被建立的一個軟體機器本質上講可以執行在任何計算機上——甚至可以被建立為一個新的平臺,它使用Java 位元組程式碼作為它自身的機器指令。換句話說,Java 虛擬機器可以用硬體或用軟體實現,而Java 程式並不“知道”其中的區別。事實上,如果Sun Microsystems JavaStation(一種被稱為計算機的想法)直接執行Java 位元組程式碼(我不能肯定的說),我們可以認為Java 程式是在由軟體實現的 Java 虛擬機器上模擬。在一個完全不同的計算機上模擬為另一個計算機結構編寫的程式這一概念當然並不新鮮。例如,一些十分熱愛他們舊的8位遊戲的人們費盡心機的使自己可以在 PC 上繼續玩。但Java 精確定義的語言規格和虛擬機器目的在於使其可以執行在不同的結構上。這成了Java 被那些關心跨平臺移植性的人們感興趣的核心因素——它提供了一個精確定義的語言和虛擬機器規格,使在任何計算機平臺上建立虛擬Java 計算機成為可能。

這在理論上講的確很好,但對此文持懷疑態度的批評家卻更關心在不同的程式碼基礎和不同的平臺上提供相同的行為所面臨的巨大挑戰。事實上,大量的相當新的 Java 實現正在被公開,因此我們可以開始收集新理論變成實際的成功資訊。如果我不得不決定是否推薦轉向 Java 利用它的跨平臺特性,我將仔細的研究 Java 實際的相容性優點。(正象Ronald Reagan 所說的)至少,我將在我打算執行軟體的每個地方測試它,對我發現的問題我將提出自己的看法。“吱吱響的輪子會得到加油,不響的輪子卻會壞掉。”

如果你讀過基礎知識文章Q154580,“Just-In-Time 編譯器描述”(MSDN 基礎知識庫),你會看到程式碼在虛擬機器上被執行之前透過將 Java 位元組程式碼編譯為不同的原生程式碼可以改變 Java 的執行特點。因此,取代解釋該程式,你可以正常的執行它。這給了你在原始碼級上的移植性,使你可以保留程式的優點,在首選位置為自己的計算機編譯高效的程式碼。

從自稱對可移植性無所不知的人們中我聽說一個正在醞釀的強烈的意見:C 語言狂熱者聲稱透過重新編譯 C 語言也可以移植,Java 的狂熱者卻說重新編譯是移植性問題的一個可悲的藉口。我塞上耳朵不理會這些——一旦你理解了 Java 語言的解釋方面的特性(這使得對跨平臺的支援到了原始碼級)正是 Java 可移植性的重要部分,那些說法幾乎是毫不相關的。

並不是另一個

解釋型的語言本身並不意味著它的程式自然可以有跨平臺的相容性,因為程式中的所有因素取決於其下的。世界目前還沒有一個公用的方法來從不同的作業系統中獲取這些要素(如果你不要求 Java 這樣做)。因此,除了掌握他們首選的程式語言外,者堅持學習不同的應用程式程式設計介面,或者 API。即使你對 C 語言熟悉的就象自己的手背一樣,要開發各種各樣平臺上的 C 應用程式意味著你必須也要成為一個各種 API 的專家。事實上,目標平臺上提供的各種 API 之間的區別是設計可移植程式的關鍵。Sun 透過為他們定義的“Java相容”的平臺描述一個標準的 Java API 來解決可移植這個複雜的問題。但是你知道什麼呢?對於任何支援跨平臺 Java API 這個概念都十分有效。將語言的概念與作業系統特定的 API 相合並都象在說:“如果你打算用 C 語言程式設計,你必須使用® API”。冒著可能受到限制的危險,將語言的概念與 API 組合成一個單一的包的確是面向建立可移植軟體邁出的一大步。瞧!我現在理解了 Java 的真實含義。它不只是一個語言,或僅僅是一個 API,而是兩者的結合!

將語言和 API 合成一個單一的源,有一個潛在的缺點:如果你不喜歡 API,或所需的部分沒有釋出,或者你發現其中的許多問題等等,你將無能為力。但是,Java API 可以被擴充套件,實際上 Sun 的 Java 小組正努力解決在已釋出的兩個版本中諸如過分簡單的圖形和多支援此類的問題(參見)。當然,當不能透過對現存 Java 虛擬機器頂層類派生的方法實現所需功能時,可以擴充套件 Java API,同時又引入了新的移植性問題。如果新的 VM 在所有 Java 相容的平臺實現這些擴充套件之前釋出,作為擴充套件加入標準 Java VM 的新內容將導致新的問題。原先下載新 VM 的煩惱將會刺激人們,尤其是如果他們的 VM 是瀏覽器固有的一個部分時,他們將不得不連同瀏覽器一同升級。另一方面,如果對 VM 的擴充套件不能在所有的平臺上實現時,將帶來問題。

由於 Java 是被解釋的,在 Java 中建立新類庫是另一個擴充套件跨平臺 API 的方法。這也就是說,透過使用 Java 語言本身你就能以一種完全可移植和相容的方式進行功能擴充套件。當然,如果你不能解決關鍵性問題或下層 VM 的不足,你可能被限制去做你想做的事情。但是你的 Java 程式將是可移植的。事實上,許多公司正在釋出帶有全部跨平臺和擴充套件功能特性的 Java 類庫——例如,微軟新的應用程式基本類(AFC)。關於 AFC 的更多的資訊,參見。

在 JDK 1.0.2 和 1.1 版中,22個 Java 使用者介面類描述了一套必須使用本地機作業系統實現的物件。為了實現這些,Java 將這特殊的22個類中的每個類與一個對等物件聯絡。對等物件負責繪製該物件和處理使用者輸入的事件。這22個類是高階視窗工具包的一部分並在 Java 和 Java VM 的原生程式碼之間提供了一個明確定義的互動作用,同平臺特有的外觀和感覺一樣(參見 上的“元件結構的細節”)。一個對等物件用本地方法實現它的大部分功能。如果在基於® 機器上你用器跟蹤自己的 Java 程式碼到一個本地方法,並單步執行到原生程式碼,另一端將出現在 Windows 動態連結庫(DLL)中。如果你象我一樣總是喜歡知道事物是如何工作的,你可以檢視微軟的 來查詢微軟的 Java VM 的本地方法是如何作用的(在左邊的幀中單擊“Raw Native Interface”)。我仍舊敘述平臺特定的外觀和感覺部分是如何工作的(和它是如何改變的),因為我認為在跨平臺移植中這是關鍵性的一章。

在容器中佈局使用者介面元件也有潛在的移植性問題(參見 ),因為 Java 透過一個允許插入定製管理器的佈局管理器體系結構放置元件到指定的位置。為了確保可移植性,包含其它物件的物件不能過分注重所包含物件實際所處的位置。否則,容器程式碼中需要處理象螢幕解析度、容器尺寸、檢視屬性和其它無關的細節。透過將 Java 容器物件和佈局管理器物件聯絡,你可以一次性解決佈局問題。你可以透過定製佈局管理器在容器中建立各種檢視(參見 Java 指南http://www.javasoft.com/nav/read/Tutorial/ui/layout/custom.html)。例如,能夠插入自己的佈局管理器用 AFC 替代 Sun 的實現方法,創造性的將ActiveMovie™ 內容放入ListView 容器。因此,如果你注重自己的 Web 頁面在不同螢幕解析度下的外觀,或要在容器中放入新元件,Java 的佈局管理器介面可以是一個解決方法。

移植性更好的語言

總之,Java 語言本身的要素使它十分方便的就可以建立跨平臺的應用程式。這並不意味著你不能透過其它方式實現可移植性,例如,透過使用帶有類似 C 這樣完善的引用庫的 C 語言。正如我已經陳述的那樣,建立可移植的軟體主要是有一個合適的程式的問題。然而,從可移植性的觀點看 Java 語言已經為此作了許多工作。

例如,象我前面提到的那樣,Java 的締造者努力使語言的任何方面都不依靠 Java 的實現來決定。例如,取整型變數的尺寸。在 Java 中,short型總是16位,long型總是32位。變數尺寸嚴格的定義比 C 語言更有限制性,C 語言中整型的尺寸可以隨結構增長,但它比僅僅確保 sizeof(short) <= sizeof(int) <= sizeof(long)有更好的可移植性。類似的,Java 的浮點型變數的尺寸也是固定的(所有浮點運算遵守一個標準 IEEE 754。參見“計算機體系結構原理”的)。實際上,Java 語言規範中精確定義了在 ANSI C 中留給獨立實現的所有基本資料型別的尺寸。

擴充套件精確定義資料型別尺寸的概念,Java 語言固定使用專有地Unicode version 2.0 字符集。如果你曾經為在支援不同字符集的平臺之間複製一些程式碼而高興,那麼你會認為固定字符集是多麼令人憤怒。當然,你可以使用 Unicode 字符集的 ANSI 內碼表,但是你的字元將不在是8位的,因此你不會看到任何 Java 源的在 #ifdef 多字符集上出問題。由於這個原因,你不會看到任何 #ifdef,因為 Java 沒有預處理。Sun 的 Java 小組指出你並不需要它,因為 Java 提供了更好的方法來實現等價於 #define語句和條件編譯的功能,而條件編譯通常用於處理不同的依賴於平臺的程式碼的路徑選擇。目前為止我還沒有發現這是一個問題,但是我認為我還沒有完全信服。

在 API 中你經常見到的許多東西在 Java 語言中都被直接取代,許多在跨平臺程式碼中不可移植的 API 元素在 Java 中都成為可移植的。例如,同步就包含在其中。如果你有 Win32 背景,你很熟悉同步對於保護程式碼中命名部分的作用。在 Java 中,同步被指定在物件級。這意味著你的應用程式的設計滿足在一組自然發生的可重複使用的物件中同步的需求。當然,沒有理由不讓你建立特殊的 Java 類,就象在“乾脆的” Win32 程式碼中臨界區的用法一樣使用該類。

執行緒是經常在 API 中見到的另一個領域,但是已經被直接建立到 Java 語言中。在 Java 中,確定你的執行緒模型與從自己的應用程式中提取它包含的任務或物件緊密相關。與同步一樣,Java 將化建立在物件級鎖定中,Java 的方法將你的執行緒活動放在一個物件級別上。與我的傳統觀念相符,我將 Java 的功能與 Win32 的功能相比較,發現 Java 的不足。例如,用等待函式來同步物件(在 Java 中這是唯一實現多執行緒執行同步的方式),而這僅僅是 Win32 中控制執行緒方式中的一種。Java 僅僅提供了單一物件的排程方法,不能在多個阻塞的物件中指定要排程的執行緒,而 Win32 提供了多物件的排程和預警等待函式(在 MSDN 庫中的 SDK 平臺中查詢“Wait Functions”)。如果你正在處理 Java 的限制,你最好確保你的程式不會與將來的 Java 版本衝突。

當今軟體最大的可用性問題之一併不是粗糙的使用者介面設計。而是比那簡單的多的問題——軟體的小缺點。Java 採取一個實際的方法來解決那些普遍存在而又無法預料的程式錯誤;透過將選中的異常作為語言整體的一個部分和在 JDK 的類實現中丟擲適當的異常,強迫開發者考慮當他們的程式失敗時如何處理。在編譯時,選中的異常允許編譯器校驗是否有一段程式碼來處理執行該函式時可能發生的問題。換句話說,除非你正確的處理了自己的錯誤,否則你不會透過編譯檢查,實現單獨執行。多麼好的概念啊!可什麼時候才是你最後一次為無法解釋的軟體錯誤痛苦的時候呢?以我的經驗,建立健壯的軟體需要在每行程式碼編寫前都要有專業的協調努力,我很欣賞 Java 所提供的額外的標準來確保確實進行了這種努力。當然,一些 C++ 編譯器(包括微軟的)有異常檢查,但是這個特性不是可以與 API 合為一體的標準的語言要素。編譯時的錯誤檢查提供了另一個將語言的概念與有優點的 API 合併的例子。(在 Web 上,我遇到這樣一篇文章“的經驗”如果你對此感興趣可以去看看)

你是否真的關心可移植軟體?

當我自學 Java 時建立的 Applet 是我曾經編寫過的不需任何“額外”工作(除了測試,當然也有一些小毛病需要我改正)就可以在多個平臺上執行的程式。另一方面,我已經與許多關心可以在任何地方執行的軟體開發者談論過這些,但還沒有被他們所信服。畢竟,Windows 和 MS-DOS® 佔據著我們時代的統治地位。但是核心平臺的觀點忽略了在 Web 上只有內容才是核心的事實,你需要每個人都能夠訪問你的內容不論是現在還是將來。

即使你不關心可移植性,也會有其他人去做。例如,在企業中,在所有大型機、、桌上型電腦、行動式和手持式之間的自動相容可以極大的減少程式設計量和技術支援。當然,Web 出版物可以到達各種 工作站和 Windows CE 手持式 PCs。

我曾經與一些認為 Java 是被過分宣傳的、將很快成為失敗的被忘記的技術的人們討論過。另一些人們相信對 Java 的將來如此暗淡的估價是生活在過去的人們的自嘲。我認為事實可能是在兩者之間中間結果:Java 是一個工具,象其他工具一樣,只有被正確的使用才能體現它的價值。

如果你覺得這篇文章對你有幫助,或你有什麼建議、苦惱、問候,請發 給 讓我瞭解。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988207/,如需轉載,請註明出處,否則將追究法律責任。

相關文章