Java程序語言和環境的設計目的是為了解決現代程序設計上的問題。它最初是一項較大規模『消費者電子產品先進軟件發展專案』的一部份,該專案目的是為了發展小型、可靠、可移植、分布式、實時的嵌入式系統。我們在專案一開始原決定采用C++,不過碰到一些問題。最初,那只是編譯器技術方面的問題,可是后來我們遭遇更多困難,且發現最好的解決方式就是更換編程語言。
(1) Java
Java是一種簡單、面向對象、分布式、解釋、健 壯、安全、結構中立、可移植、高效能、多線程、動態的語言。描述系統特性的方法之一就是把一堆高效能的術 語擺在一起。一如上述,我們也使用一組標準的術語來描述Java。以下我們將解釋這些術語在 Java上代表的意義,以及我們試圖解決的問題是哪些?!菏紫?,我們要介紹阿基米得公司(Archimedes Inc.);它是我們為了方便說明Java功能而虛構的一家軟件公司。阿基米得從事有關基本物理教學 用途的軟件開發,其軟體設計目的是要與使用者產生交互關系,不僅提供一如傳統教科書的文字 與插圖,而且也包括一組軟件實驗工作室,供使用者進行實驗和模擬真實世界的物理行為。例 如,它最基本的一項實驗允許學生組成杠桿和滑輪,然后觀察它們的物理作用。在以下的論述 中,我們將借由這些實驗和阿基米得設計師的旁白,以說明Java語言概念?!?/P>
(2) 簡單
我們想建立一種真正簡單的系統,它允許使用者 輕易地設計程序而不需要像現今的標準程序一樣接受深奧的訓練。目前大多數程序設計師都采用 C語言,而面向對象程序設計師則大多使用C++。因此,即使我們發現C++并非適合我們,我 們在Java的設計上還是盡可能讓它與C++相近,以確保系統更容易被理解。Java刪除許多極少被使用、不容易理解和令人混淆 的C++功能,這些功能在我們的使用經驗中只能帶來麻煩而非效益。刪除的功能主要包括運算符 重載(operator overloading)、多重繼承(inheritance)以及廣泛的自動強迫同型(automatic coercions); 重載是指以一個辨識元參照多重項目,Java語言也提供重載函數,不過它重載的對象是方法(method)而非變量或運算符。我們增加自動內存垃圾收集(auto garbage collection) 功能,因此簡化Java程序工作,不過同時也讓系統變得稍復雜一些。儲存管理(storage management)是使C與C++ 應用程序變得復雜的常見的一項原因,即關于內存的分配與釋放。Java語言的自動垃圾收集功能(周期性地 釋放未被使用的內存)不僅簡化了程序設計工作,而且能大幅度減少小錯誤(bugs)數量。『阿基米得設計師們原想花時間思考杠桿與滑輪原 理,但是后來卻發現大部份時間都浪費在世俗的程序工作上。事實上,他們的核心專業知識在于 教學而非程序設計。這些程序工作中最復雜的部份就是從他們那二萬行程序碼中,找出那些地方 浪費了內存。』 確保Java『簡單化』的另一特性在于『小而單 純』。Java的目標之一是要協助開發能獨立地在小型機器上順利執行的軟件。Java的基本解釋器 (interpreter)和對象類(class)支援約占4OKB,而若增加基本的標準程序庫和線程(thread)支援 (它 實際上是一整自含式的微核心) 需增加175K。體積小對于在嵌入式的系統中的使用是很重要的,并因 此Java可以通過網絡輕易下載。
(3) 面向對象
這是在業界被過度渲染的術語之一。不過,面向 對象是一項很強的設計功能,因為它促成明確的接口定義,并允許發展者建立可重復使用的『軟 件IC』。簡單的說,面向對象設計是一種以數據(對象) 及其接口為重心的程序設計技術。我們以木匠比例;一位『面向對象』木匠最重視的是他想制作的椅子,其次才是他用來制做椅子的工具。相反的,一位『非面向對象』木匠是把主要的心思放在工具上。面向對象設計也是定義程序模塊如何『即插即用』的機制。Java的面向對象設施實質上就是C++,并包含 Objective C的一些延伸,以提供更有動態的解決方案。『阿基米得設計師在他們的模擬式中設計許多 東西,包括繩子與橡皮筋等。他們初期的C版本產品是一個非常龐大的系統,因為他們必須個別地設計軟件來描述繩子和橡皮筋。當以面向對象方式重新設計應用程序時,他們發現可以定義一個基本對象來代表繩子與橡皮筋兩者之間的共同部份,然后繩子與橡皮筋即定義成基本對象類型的子對象類。其后,當他們有需要增加鏈結時就能非常輕易地建立起來,因為他們可以將這些鏈結建立在先前已設計妥當的對象之上,而不需要整個重新設計新對象模擬?!?/P>
(4) 分布式
Java擁有廣泛的例程庫(routine library)能輕易地處 理TCP/IP協議,例如HTTP與FTP等。這使得在Java中比在C或C++中更容易創建網絡連接。Java應用程 序可以借由URL在通過網絡開啟和存取對象,就如同存取一個本地(local)文件系統一樣簡單。 『阿基米得設計師最初把他們的程序建立在CD-ROM上。不過他們想把一些交互式教學游戲程序 概念放在下一個產品內。例如,他們想讓不同電腦上的學生一起建立一臺模擬機器供大家學習。 不過,他們評估過的所有網絡系統都過于復雜且要求深奧的軟件工程專業能力。于是,他們只好 放棄這個概念。』
(5) 健壯
Java的目標是要協助發展者建立各方面都必須 可靠的程序。Java強調在設計初期即檢查可能存在的問題,其后則執行動態(runtime)檢查,并排除 容易出現錯誤的條件。強類型(strongly typed)語言例如C++的優點是允許 在編譯時進行深入的檢查,以便提前發現錯誤。不幸的是,C++承襲了C在編譯檢查(compile-time checking)時的一些漏洞;C的檢查較為松散,特別是在方法/過程聲明方面。我們在Java中要求 聲明,但并不支持C風格的隱性聲明。鏈結器(linker)了解類型系統并重復執行許多 已由編譯器完成的類型檢查,以避免出現版本不匹配問題。Java與C/C++之間最大的不同點之一在于Java擁有 一種指針(pointer)模型,能排除發生內存被覆蓋和毀損數據之可能性。Java不采用指針算 術法,而是提供真正的陣列。這允許程序執行下標檢查;再者,它也不可能發生借由對象 類型轉換將一個任意整數轉成指針的情形。『阿基米得設計師的應用程序在C執行時基本上相 當快速。不過他們的軟件開發日程一再落后,因為總有清理不完的小錯誤逃過他們的檢查。他們 面對許多麻煩,包括內存分配失敗、版本不一致、接口不匹配等。C讓他們能在程序碼中增加一些 巧妙的設計,然而卻必須因此付出時間代價以求確保程序品質。由于錯誤清不干凈,因此他們的軟件推出第一版之后就得忙著寫修補程序?!籎ava雖不能排除品質確認問題,不過它讓這道程 序變得簡單許多。許多動態語言例如Lisp、TCL與Smalltalk等,通 常被用來制作原型程序(prototyping)。它們在這方面成功的理由是因為它們都非常健壯(robust),讓程序設計師不再怕處理內存問題,因為他們不須擔心內存失敗。Java即擁有這項特性。Java 程序員相對地可以不害怕處理內存問題,因為在Java中不存在指針,Java程序不可能意外覆蓋一 片內存緩沖區的末尾。Java程序也不可能非法訪問內存,但這些在C或C++中都有可能發生。動態語言適合開發原型程序發展的理由之一,就 是它們不會在發展初期就要求你擬定明確的決策。Java剛好相反,它強迫你明確地做選擇。這些選擇伴隨許多輔助:你可以編寫方法調用(method invocations),而如果你有某些錯誤的地 方,你將會在編譯時獲得通知,而不須擔心方法調用上的錯誤。
(6) 安全
Java設計目的是要供使用于網絡/分布式運算環 境。為此,Java非常強調安全性,以確保建立無病毒且不會被侵入的系統。Java的驗證技術是以公鑰 (public-key)加密法為基礎?!航研浴慌c『安全』之間存在一種很強的相互 作用關系。例如,指針語意的改變,讓應用程式不可能偽造對象結構存取權,或存取它們在對 象中沒有存取權的私有數據。這等于關起大門,阻絕大多數病毒活動。『有人為阿基米得的PC版軟件寫了一個有趣的修 補程序,然后將它貼到一個主要的電子布告欄上面流通。由于這支修補程序很容易取得而且又能 為系統增加一些有趣的功能,于是很多人都下載使用。這個程序未經阿基米得設計師檢驗過,不 過它用起來似乎還不錯。直到四月一日那天,好幾千名使用者發現他們小孩使用的教學軟件突然 跳出幾張不堪入目的圖片。不用多加說明,阿基米得設計師們雖不用為這個意外負起責任,但是 他們還是必須設法控制那個修補程序造成的破壞。』
(7) 結構中立性
Java的設計目標是要支援網絡應用程序。一般而 言,網絡是由許多不同的系統構成,包括各種CPU與操作系統結構。為了讓Java應用程序能夠 在網絡上任何地方執行,其編譯器會產出一種具備結構中立性(architecture neutral)的目標文件格 式。編譯后的程序碼可以在提供Java runtime系統的多種不同處理器上面執行。這不僅對網絡應用很有幫助,而且也很適合單一 系統軟件流通。在目前的個人電腦市場上,應用程序發展者必須為他們的程式分別編寫IBM PC 和Apple Macintosh相容版本。現在,PC市場正(透過Windows/NT)分散成許多CPU結構,而 Apple則從68000轉向PowerPC,這些事實使得我們幾乎不可能設計出能在所有平臺上執行的軟體。Java允許同一版本的應用程序在所有平臺執行。Java編譯器是借由產出與某一電腦結構無關的字節代碼指令,以達到上述功能。它們能輕易地在任何機器上解釋,并且動態地轉換成原生模式 的機器碼?!喊⒒椎檬且患倚」?。他們從設計PC軟件起 家,因為那是最大的市場。經過一段時日之后,他們成長至規模夠大的公司,因此有能力為 Macintosh平臺開發軟件,不過那確實是一項很大的工程,而且投資報酬并非真的很好。他們無力 負擔將軟件移植到PowerPC Macintosh或MIPS。NT機器所涉及的人力與成本。當第一波潮流來臨 時,他們未能捉住機會,而競爭者即趁虛而入?!?/P>
(8) 可移植性
結構中立性是確保程序可移植的最重要部份,不 過除此之外還有很多條件必須配合。和C與C++不同的是,Java規范中并無任何『結構相依性』的陳述存在。它指定基本數據類型的大小,以及其算術運算元之執行行為。例如,"int" 代表一 個有符號的二進制補碼32比特整數,而"float"代表一個32比特IEEE 754浮點數。這些選擇在 今天的環境很適用,因為幾乎所有CPU都具備這些特性。程序庫屬于系統的一部份,它定義了一些可移植 的程序接口。例如,它包括一個抽象的Windows類,并且提供了類在Unix、Windows和 Macintosh平臺上的實現。Java系統本身具備相當好的移植性。編譯器以Java 寫成,而runtime程序使用ANSI C,并有一個實質上與POSIX相容的移植疆界(portability boundary)。"
(9) 解釋
Java解釋器(interpreter)可以直接在任何已移植解 釋器的機器上解釋、執行Java字節代碼,不需存儲。再者,由于其鏈結比較傾向于逐步增量與輕量過程, 因此發展程序更快、更精密。由于編譯期間的信息屬于字節代碼資料流的一部 份,因此可以在運行期間攜帶更多的信息。這正是鏈結器類型檢查的基礎,它也讓程序更容易執行除錯?!喊⒒椎迷O計師花很多時間等候程序編譯和鏈 結。他們也花很多時間追蹤許多無法感測到的錯誤,因為有些更改過的原始檔案未能完成編譯程 序 (雖然他們使用了make公用程序) 而導致版本不一致。同時還要追蹤一些在程序中許多聲明不 一致的程序。于是,他們的軟件發展日程又延誘
幾個月?!?/P>
(10) 高效能
雖然解釋過的字節代碼性能已相當不錯,不過有 些情形下還是要求程序達到更高執行效能。字節代碼可以動態地(runtime)為執行應用程序的 特定CPU解釋成機器碼。這對于習慣使用一般編譯器與動態載入器(loader)的設計者而言,有點類似將最終的機器碼產生器放到動態載入器之內。字節代碼格式在設計上即顧及機器碼的產生,因 此實際的機器碼產生程序相當簡單。產出的機器碼是有效的,編譯器自動分配寄存器,而 在產出字節代碼時也會進行一些優化。我們以解釋碼在一臺Sun Microsystem SPARC Station 10上執行時,達到每秒三十萬個方法調用(method calls)速率。字節代碼轉換 至機器碼的速度性能,幾乎和原生模式的C或C++沒有兩樣?!寒敯⒒椎霉緞偝闪r,他們 用Smalltalk設計原型程序。這協助該公司獲得投資者贊助,不過那并沒有真正的幫助他們生產產 品:為了讓他們的模擬程序跑得夠快并符合精簡系統要求,他們只好用C重新設計?!?/P>
(11) 多線程
在真實世界中,許多事情同時發生在我們身邊。 多線程(multithreading)是一種應用程序設計法。不幸的是,要設計一個一次同時處理許多事 件的程序,比設計傳統單一線程C與C++程序來得復雜許多。Java擁有一組復雜的同步化基本單元,它們 是以廣泛使用的C.A.R. Hoare監視器與條件變量圖為基礎。將這些概念溶合到語言之后,它們即變得 很容易使用且更為健壯。這項溶合方式大部份來自Xerox的Cedar/Mesa系統。多線程的其他效益包括更好的交互式回應能力 與實時執行行為。然而這會受到底層平臺的限制:獨立執行的Java運行環境有著很好的實時執行行 為,而若在其他系統例如Unix、Windows、Macintosh或Windows NT等之上執行則由于底層 平臺的原因實時反應性將會受到影響。『阿基米得的模擬程序一次同時執行許多項實 驗:拉動繩子、轉動輪子和 「 桿,同時還追蹤使用者輸入。由于他們必須將這些模擬全部設計在一個單一線程的程序格式內,因此所有同時發生的動作 (不論彼此之問是否有關系) 必須用人工方式予以混合。使用一個事件回路可以讓情況更清楚一些,不過那仍舊是一團混亂,系統變得很脆弱而難以理解。他們從整個網絡擷取數據,不過最初他們只能一次抓一個區塊,這種串行的網絡通訊非常緩慢。當他們轉移到多線程模式之后,網絡通訊問題即迎刃而解。』
(13) 動態
從許多方面而言,Java是一種比C或C++更具動態 特性的語言。它在設計上強調為進化中的運算環境提供支援。例如,C++在生產環境中的主要問題之一在于該 程序碼在一般設計上引起的負作用。如果甲公司設計一個對象類程序庫,而乙公司采購后它并 放到自己的產品中使用,然后如甲公司更改其程式庫并提供新的版本,那么乙公司將幾乎可以確定必須重新編譯和重新流通他們的新軟件。當最終用戶分別向甲乙兩家公司購買軟件 (例如甲 是作業系統廠商,而乙是應用程序廠商) ,那么問題就產生了。例如,如果甲公司為其程序庫供應一種升級版 本,那么乙公司的所有軟件都將必須修改。雖然C++可以避免此一問題,不過那極為困難,而且它也意味著不能直接使用該語言的任何面向對象功能。『阿基米得采用3DPC公司提供的面向對象圖形程 式庫建立他們的產品。3DPC后來推出新
版本的 圖形程序庫,并且有數家電腦制造商將它搭配在 新機器上出貨。采購這些新機器的阿基米得客戶很失望地發現他們的舊軟件不能繼續使用。 (在 真實世界中,這種情形只發生在Unix系統上。在PC領域里,3DPC將永遠不會推出這樣的程序庫,因為他們更改和使用C++面向對象功能的能力受到極大的限制。 )』
Java是在稍后的階段為模塊與模塊之間建立這些 連接,因此完全避免了這些問題,并能更直接地運用面向對象設計體系。程序庫可以自由地增加 新方法和實例(instance)變量,而不會對它們的用戶產生任何效應。Java能了解由Objective C引用過來的接口概念。 簡單的說,接口就是規范一組與對象相對應的方法,但對象如何實現這些方法則留待解決。一個 類實現一個接口是要提供這個接口所包含的所有方法的實現。以此相反,派生子類則從父類繼承 了一組方法以及它們的實現。一個Java類可以實行多個接口,但只能從一個父類繼承。接口告訴連接對象它可以做什么而非怎么做,使得它在代碼上更具有靈活性和可復用性。對象類有一種運行(runtime)表示法:它有一種類稱 為Class,其內容包括runtime class定義。在C或C++程序中,如果你有一個指針指向一個對 向,但你不知道該對象的類型為何,那么你將沒有辦法找出它。然而,在Java中要根據runtime類 型信息尋找是很直截了當的。因為,在compile-time和run-time時都會檢查數據類型轉換,所以 你在Java中可以信任這種轉換。另一方面,C與C++的編譯器則只是相信你已做了正確的處理。此外,它也可能從一個包含名稱的字串查找一個 對象類別定義。這意味著你可以演算一個數據類型名稱,然后輕易地以動態方式鏈結到執行系統。『阿基米得為擴充營收源,希望讓他們的產品能 利用新的 入式模塊來擴充系統。這種擴充以前在PC上是可能做到的,只是很少實現。他們必 須增加一些新程序設計員,因為那些工作很復雜,而且也增加許多除錯問題。』
(14)總結
Java語言提供一種強有力的工具支援程序設計員。 Java讓程序設計變得更容易,因為它屬于面向對象語言,而且提供了自動的內存垃圾收集功 能。再者,由于Java碼具備結構中立性,因此其應用程序成為非同質性運算環境 (例如Internet) 的理想方案。
posted on 2005-02-04 11:40
jacky 閱讀(326)
評論(0) 編輯 收藏