Java之所以被開發,是要達到以下五個目的:
應當使用面向對象程序設計方法學
應當允許同一程序在不同的計算機平台執行
應當包括內建的對計算機網絡的支持
應當被設計成安全地執行遠端代碼
應當易於使用,並借鑒以前那些面向對象語言(如C++)的長處。
Java技術主要分成幾個部分:Java語言、運行環境JVM、類庫。一般情況下說Java時並不 區分指的是哪個部分。
面向對象
Java的特點之一就是面向對象,是程序設計方法的一種。“面向對象程序設計語言”的核 心之一就是開發者在設計軟件的時候可以使用自定義的類型和關聯操作。代碼和數據的實際 集合體叫做“對象”。一個對象可以想象成綁定了很多“行為(代碼)”和“狀態(數據) ”的物體。對於數據結構的改變需要和代碼進行通信然後操作,反之亦然。面向對象設計讓 大型軟件工程的計劃和設計變得更容易管理,能增強工程的健康度,減少失敗工程的數量。
面向對象設計另外一個目標就是能產生很多的有關聯的類,可以讓軟件的再開發變得簡單 。舉例來說,很多軟件工程都有同樣的功能,尤其是很多應用了同一原理組織的軟件工程。 軟件的二次開發者想自己為軟件開發插件以增強功能的時候,絕對不想看到混亂的開發代碼 和管理計劃。面向對象的目的就是不生產難懂且難以使用的代碼,為軟件各個功能群之間建 立有效的通信通道。很多開源軟件社區正在計劃給軟件作者提供更多的類來讓軟件的二次開 發變得簡便。
跨平台性
一個Java軟件的界面,在所有系統下面都可以運行這個程序
Java語言的第二個特性就是跨平台性,也就是說使用Java語言編寫的程序可以在編譯後不 用經過任何更改,就能在任何硬件設備條件下運行。這個特性經常被稱為“一次編譯,到處 運行”。
執行Java應用程式必須安裝 Java Runtime Environment(JRE),JRE內部有一個Java虛擬 機器(Java Virtual Machine,JVM)以及一些標准的類別函式庫(Class Library)。通過 JVM的虛擬機才能在電腦系統執行Java應用程式(Java Application),這與.Net Framework 的情況一樣,所以電腦上沒有安裝JVM,那麼這些程序將不能夠執行。
實現跨平台性的方法是大多數編譯器在進行Java語言程序的編碼時候會生成一個用字節碼 (Bytecode)寫成的“半成品”,這個“半成品”會在Java虛擬機(解釋層)的幫助下運行 ,虛擬機會把它轉換成當前所處硬件平台的原始代碼。之後,Java虛擬機會打開標准庫,進 行數據(圖片、線程和網絡)的存取工作。主要注意的是,盡管已經存在一個進行代碼翻譯 的解釋層,有些時候Java的字節碼代碼還是會被JIT編譯器進行二次編譯。
有些編譯器,比如GCJ,可以自動生成原始代碼而不需要解釋層。但是這些編譯器所生成 的代碼只能應用於特定平台。並且GCJ目前只支持部分的Java API。
升陽對於Java的許可是“全兼容的”,這也導致了微軟和升陽關於微軟的程序不支持RMI 和JNI接口、並且增加特性為己所用的法律爭端。升陽最終贏得了官司,獲得了大約兩千萬美 元的賠償,法院強制要求微軟執行升陽公司關於Java的許可要求。作為回應,微軟不再在 Windows系統中捆綁Java,最新的Windows版本,Windows Vista和Internet Explorer 7.0版 本也不再提供對於Java應用程序和控件的支持。但是升陽公司和其他使用Java運行時系統的 公司對於微軟的操作對用戶提供無償的第三方插件和程序支持。
Java語言使用解釋層最初是為了輕巧性。所以這些程序的運行效率比C語言和C++要低很多 ,用戶也對此頗有微詞。很多最近的調查顯示Java的程序運行速度比幾年前要高出許多,有 些同樣功能的程序的效率甚至超過了C++和C語言編寫的程序。
Java語言在最開始應用的時候是沒有解釋層的,所有需要編譯的代碼都直接轉換成機器的 原始代碼。這樣做的後果就是獲得了最佳的性能,但是程序臃腫異常。從JIT技術開始,Java 的程序都經過一次轉換之後才變成機器碼。很多老牌的第三方虛擬機都使用一種叫做“動態 編譯”的技術,也就是說虛擬機實時監測和分析程序的運行行為,同時選擇性地對程序所需 要的部分進行編譯和優化。所有這些技術都改善了代碼的運行速度,但是又不會讓程序的體 積變得失常。
程序的輕便性事實上是軟件編寫很難達到的一個目標,Java雖然成功地實現了“一次編譯 ,到處運行”,但是由於平台和平台之間的差異,所編寫的程序在轉換代碼的時候難免會出 現微小的、不可察覺的錯誤和意外。有些程序員對此非常頭疼,他們嘲笑Java的程序不是“ 一次編譯,到處運行”,而是“一次編譯,到處調試”。
平台無關性讓Java在服務器端軟件領域非常成功。很多服務器端軟件都使用Java或相關技 術建立。
自動垃圾回收(Garbage Collection)
C++語言被用戶诟病的原因之一就是大多數C++編譯器不支持垃圾收集機制。通常使用C++ 編程的時候,編程師於程式中起始物件時,會在主機內存堆棧上分配一塊內存與位址,當不 需要此物件時,進行解構或者刪除的時候再釋放分配的內存位址。如果對象是在堆棧上分配 的,而程序員又忘記進行刪除,那麼就會造成內存洩漏(Memory Leak)。長此以往,程序運行 的時候可能會生成很多不清除的垃圾,浪費了不必要的內存空間。更糟糕的是,如果同一內 存地址被刪除兩次的話,程序會變得不穩定,甚至崩潰。因此有經驗的C++程序員都會在刪除 之後將指針重置為0,然後在刪除之前先判斷指針是否為0。
Java語言則不同,上述的情況被自動垃圾收集功能自動處理。對象的建立和放置都是在內 存堆上面進行的。程序或者其他的對象可以鎖定一塊棧地址來進行其他對象的引用。當一個 對象沒有任何引用的時候,Java的自動垃圾收集機制就發揮作用,自動刪除這個對象所占用 的空間,釋放內存以避免內存洩漏。但是內存洩漏並不是就此避免了,當程序員疏忽大意地 忘記解除一個對象不應該有的引用的時候,內存洩漏仍然不可避免,不過發生的幾率要比不 啟用垃圾收集機制的C++程序少很多。但是總體來講,自動垃圾收集機制要安全和簡單許多。
不同廠商、不同版本的JVM中的內存垃圾回收機制並不完全一樣,通常越新版本的內存回 收機制越快,IBM、BEA、SUN等等開發JVM的公司都曾宣稱過自己制造出了世界上最快的JVM, JVM性能的世界紀錄也在不斷的被打破並提高。
IBM有一篇有關Java內存回收機制比不啟用垃圾收集機制的C++內存處理快數倍的技術文章 ,可在如下網址找到:
http://www-128.ibm.com/developerworks/cn/java/j-jtp09275.html
而著名的Java技術書籍《Java編程思想》(《Thinking in Java》)也有一段論述Java內存 及性能達到甚至超過C++的章節:
http://www.sdau.edu.cn/support/thinkinjava/chapter/appe.htm
但是應該注意到,C++中也可以使用“智能指針”(Smart Pointer)或者使用C++托管擴 展編譯器的方法來實現自動化內存釋放,智能指針可以在標准類庫中找到,而C++托管擴展被 微軟的Visual C++ 7.0及以上版本所支持。智能指針的優點是不需引入緩慢的垃圾收集機制 ,而且可以不考慮線程安全的問題,但是缺點是如果不善使用智能指針的話,性能有可能不 如垃圾收集機制,而且不斷地分配和釋放內存可能造成內存碎片,需要手動對堆進行壓縮。 除此之外,由於智能指針是一個基於模板的功能,所以沒有經驗的程序員在需要使用多態特 性進行自動清理時也可能束手無策。
當然,作為一個“負責任”的程式編撰員,在程式完結前應該手動清理不再需要的變量和 物件,令效能有點提升。以Java為例,finalize方法位於 java.lang.Object 內,而Object 這個類是每一個類自動承繼的。因此清理需要的便是覆寫finalize便行了
protected void finalize() throws Throwable{
super.finalize();
}
當中若有任何變量要清理,可以在super.finalize() 前加上 <變量> = null; 或 <所屬的Class>.<變量> = null;
不過事實上,就算使用了 finalize(),你還是不能保證你在堆棧中所使用的空間會馬上 被回收,垃圾回收機制只有在你的你堆棧已經毫無空間可以使用的情況下,才會真的去進行 回收的動作,因此在編程上,還是要避免內存空間的浪費。
接口和類別
Java自帶了創建接口的類別,可以這樣使用:
public interface Deleteable {
void delete();
}
這段代碼的意思是任何實現(implement)Deleteable接口的類別都必須實現delete()方 法。每個類別對這個方法的實現可以自行定制。由此概念可以引出很多種使用方法,下面是 一個類別的例子:
public class Fred implements Deleteable {
//Must include the delete () method to satisfy the Deleteable interface
public void delete() { //code implementation goes here
}
//Can also include other methods
public void doOtherStuff() {
}
}
在另外一個類別中,可以使用這樣的代碼:
public void deleteAll (Deleteable [] list) {
for (int i = 0; i < list.length; i++) {
list[i].delete();
}
}
因為隊列中所有的對象都可以使用delete()方法。Deleteable隊列中包含Fred對象的引用 ,而這個類別和其他Deleteable類別在使用deleteAll()方法時候不需要進行任何改變。
之所以這樣做就是為了在接口的執行和其代碼之間進行區別。舉例來說,一個名叫 Collection的接口可以包含任何對象所需要的引入、轉換和存儲數據的方法,其他的類都可 以使用這個接口。但是這個接口可以是一個可重定義大小的隊列、一個鏈表或者是其他功能 的集合。
這種特性其實是一種折中的辦法。Java的設計者們不想讓Java有多重繼承的特性,因為 C++的多重繼承顯示了這種特性的困難。Java的接口功能可以提供同樣的功能,但是又不會很 復雜。