如果您是一位正在尋求將現有的電子商務應用程序移植到 J2EE 的 ASP 開發人員,或者是一位正在從頭編寫新的 J2EE 應用程序,但不想經歷“超負荷信息”的困擾就能著手編寫程序的 ASP 開發人員。那麼這個路標圖就是為您准備的。本路標圖是專為想要迅速轉到 J2EE 的 ASP 開發人員准備的,J2EE 是使用 Java 語言開發 Web 應用程序和其他類型的分布式應用程序的一個平台無關的開放標准集。同時,我們將向您介紹 J2EE,如何使用 Java 語言編程,如何開發 J2EE Web 應用程序,以及如何將這些知識與您在為 IIS 和 Windows 環境編寫 ASP、COM 對象和 ISAPI 過濾器的經驗聯系起來。
為何要轉向 J2EE?
如果您不是十分渴望冒險投入 J2EE 開發環境,請考慮以下這些 J2EE 好處:
選擇,更多的選擇:由於 J2EE 是一個定義良好的標准集,所以在部署自己的代碼時有許多 J2EE 實現可供選擇。只要您堅持使用標准 API,避免使用廠商專用的擴展,那麼應用程序無需變更代碼就能在各種各樣的實現上運行。
我們是在說選擇嗎?:J2EE 實現在從大型機到 Wintel、UNIX 和 Linux 的各種平台上都可用。編寫應用程序一次就可將其部署在各種平台上。
我們不能就安於現狀嗎?:J2EE 包含一個用於訪問許多諸如 CICS、IMS、ERP 和 CRM 這樣的遺留 EIS 系統的標准 API。它還包括 Web 服務支持,因此您可以集成 .NET 系統和支持行業 Web 服務標准的其他系統。J2EE 還支持標准消息 API(Java Message Service; JMS)和用於訪問關系數據庫(Java Database Connectivity; JDBC)的 API。這種廣泛的選擇允許您集成各種現有系統,而不會損失您對它們的投資。
機房不再煙霧缭繞:來自世界各地的專家通過 Java Community Process(JCP)開發 J2EE 規范。JCP 發布了初步的規范草案以供公眾評論。即使您不主動參與,也總是會知道哪些未來的規范正在籌備之中。該規范還包括一個參考實現,您可以在決定實現它之前使用它來檢查新技術。
回頁首
J2EE 簡介
Java 2 Enterprise Edition 這個規范是由許多與使用 Java 語言開發分布式應用程序相關的組件規范組成的。您可以使用 J2EE 組件來編寫基於 Web 的應用程序和傳統的客戶機-服務器應用程序,以及使用標准的 API 來連接到諸如關系數據庫之類的遺留資源。如果您有 IIS/ASP 開發背景, 那麼 Java Servlets和 JavaServer Pages(JSP) 技術就是對您最有用的組件。
移植到 Java 平台
如果您開發 .NET、Windows 客戶機/服務器應用程序和 ASP 應用程序,並且想要迅速跨入 J2EE 平台,則系列文章 走上開放之路 將指導您通過該過程,利用您現有的開發知識,鋪就您走上基於開放標准的編程之路。
Java Servlet
Java Servlet 是作為諸如 IIS 或 Apache Web Server 等 Web 服務器的擴展來運行的 Java 類。Java Servlet 類似於 ISAPI 過濾器或 cgi-bin 程序/腳本。servlet 在客戶端浏覽器直接或間接地調用一個專門配置的 URL 時運行。servlet 能訪問 HTTP 請求中的所信息,並能通過提供返回給客戶端的內容來直接處理該請求。或者,servlet 能將客戶端浏覽器重定向到另一個資源。大多數 J2EE Web 應用程序都主要把 servlet 用作 HTML 表單的目標以處理用戶輸入,然後作相應的處理。響應頁面的生成通常委托給一個 JSP 頁面。
JavaServer Page 技術
JSP 頁面類似於 ASP 頁面。即它們是包含腳本元素的 HTML 頁面,在用戶請求該頁面時,這些腳本元素就會在服務器上運行。ASP 頁面和 JSP 頁面之間的一個關鍵區別在於,ASP 使用 VBScript 或 JScript 作為腳本語言,而 JSP 頁面則使用 Java 語言。典型的 JSP 頁面包含 Java 代碼片斷和一些在 JSP 規范中定義的特殊的類 HTML 標簽,它們與標准的 HTML 交織在一起,提供靜態內容和動態內容的組合。Java Servlet 和 JavaServer Page 技術之間的區別在概念上類似於 ISAPI 過濾器和 ASP 頁面之間的區別。在這兩種情況下,前者都是可用於直接或間接向其他資源發送 HTML 的一段代碼,而後者都是一個可以包含嵌入代碼的 HTML 文檔。
Web 服務器和應用服務器
作為 ASP 開發人員,您知道 ASP 頁面由 IIS 調用的腳本引擎執行。您還可以向 Web 應用程序添加 ISAPI 過濾器和 COM 組件,以供 IIS 進行調用。這種方法使得在 IIS 上部署 Web 應用程序非常容易。但這僅限於 Windows 平台,即 IIS 可以運行的唯一平台。而 J2EE 采用不同的方法,因為它的設計目標就是在各種操作系統(包括 Windows)上運行。它並非嘗試將運行 Java Servlet 和 JSP 頁面的代碼直接嵌入到 Web 服務器,而是使用一個稱為 應用服務器的單獨的服務器組件來運行它們。大多數應用服務器(如 IBM WebSphere)還擁有一個單獨的插入組件,它們在應用服務器和特定的 Web 服務器之間架起了一座橋梁。例如,WebSphere 附帶了針對 IIS 和 Apache Web 服務器的單獨插件。這樣,您在運行 J2EE 組件時就可以使用自己選擇的 Web 服務器。
應用服務器作為單獨的可插入組件這種功能帶來了許多優點:
Web 服務器選擇:您不會被限定使用某個 Web 服務器來提供靜態的 HTML 頁面。您可以繼續使用自己最喜歡的 Web 服務器來實現此目的,並且使用任何應用服務器來處理 Java Servlet 和 JSP 頁面。這種能力在您將 ASP 應用程序移植到 J2EE 時特別有用。您可以繼續運行 IIS 並分階段移植應用程序。您不需要一下子改寫整個應用程序。
平台選擇:您可以編寫 J2EE 應用程序一次,然後在能夠運行應用程序服務器的各種操作系統上部署它――包括 Windows、AIX 和 Linux。您不會被限定於某個能夠運行特定 Web 服務器的平台。
應用服務器廠商選擇:由於行業標准規范定義了 Java Servlet 和 JavaServer Page 技術,因此您可以編寫 J2EE 應用程序一次,然後將其部署到多個應用服務器環境中,如 WebSphere Express 或 Apache Tomcat,後者是一個流行的開放源代碼應用服務器。J2EE 還定義了必須如何打包 Web 應用程序,因此,您可以將自己開發的應用程序引入某個 J2EE 環境,在無需更改代碼或重新編譯應用程序的情況下,就能將它重新部署另一個應用服務器中。將應用程序部署到多個平台也是如此。
應用服務器如何運行 servlet 和 JSP 代碼
如上所述,J2EE 規范強制人們使用一種標准格式來部署 Java Servlets 和其他 J2EE 組件。一個稱為 部署描述符的 XML 文檔就是這個標准格式的一部分。部署描述符包含從每個 servlet 到用於調用特定 servlet 的 URL 的映射。應用服務器使用部署描述符中的信息來決定針對給定的請求應該調用哪個 servlet。
應用服務器調用 JSP 頁面的方式不同於調用 ASP 頁面的方式。J2EE 應用服務器將各個 JSP 頁面轉換為單獨的特殊 servlet,它在該頁面被請求時編譯和運行。這個特殊的 servlet 保持加載在內存中,直到 JSP 文件改變為止。這樣最大限度地降低了必須為每個 JSP 頁面創建和編譯一個類而對性能產生的影響。
模型-視圖-控制器體系結構
J2EE 是根據一個特定的應用程序結構開發的,這個結構稱為 模型-視圖-控制器(MVC)。MVC 清楚地將應用程序定義為三個分離的層:
模型:應用程序的數據和業務規則的集合――通常稱為應用程序的業務邏輯。
視圖:應用程序的用戶界面。
控制器:定義了應用程序如何對用戶輸入或模型層的變化作出反應――通常稱為應用邏輯。
MVC 體系結構的優點
J2EE 中沒有任何東西強迫您使用 MVC 體系結構來組織應用程序,但是這樣做有許多很好的理由。通過定義三層之間的清楚分離,MVC 允許構成每個層的組件之間進行松散耦合。這使得組件具有更高的可重用性和靈活性。例如,假設您的需求之一是在某個 Web 應用程序中對相同數據支持不同類型的視圖,因為不同的部門需要某個數據庫中相同數據的不同子集。您需要開發特定於每個所需子集的新視圖組件。如果視圖邏輯和數據庫訪問代碼是緊密耦合的――ASP 頁面就是將數據庫訪問代碼和 HTML 交織在一起,那麼每個視圖都要包含數據庫訪問代碼。維護重復的代碼不僅需要大量的工作,而且可能導致出錯。對於這種情形,MVC 體系結構將數據庫訪問代碼作為該模型的一部分,而各種視圖組件都可以重用它。
J2EE 組件和 MVC
圖 1 顯示我們到目前為止所討論的 J2EE 組件如何映射為 MVC 體系結構。注意,模型和視圖之間不存在任何聯系。控制器的功能是充當兩者之間的中轉站。
圖 1. MVC 與 J2EE Web 應用程序
在典型場景中,用戶提交一個 HTML 表單,這個表單的目標是一個 servlet。servlet 解析輸入的數據並使用模型中的類來調用業務邏輯以滿足該請求。然後,servlet 將結果傳遞給一個 JSP 頁面,以便向用戶顯示這些結果。
JavaServer Faces
JavaServer Faces (JSF) 規范提供了運行時組件,這些組件使 J2EE 工具廠商為開發基於 Web 的 UI 提供了拖放功能。它還允許廠商開發可供他們的開發工具使用的自定義組件。要了解 JSF 的實際應用,可以考察一下 WebSphere Studio 5.1.1 版中的系列工具(請參閱 參考資料)。WebSphere Studio 還有一個名為 Page Designer 的完全集成的工具,可以使用它通過拖放操作來可視化地開發 HTML 頁面和 JSP 頁面。Page Designer 已實現了 JavaServer Faces 規范,它允許您在頁面上拖放諸如 HTML 表單元素之類的組件以及一些更高級的組件,這些組件允許將 HTML 表綁定到後台數據源。
其他 J2EE 技術
Java Servlets 和 JSP 技術為您提供用 Java 語言開發平台無關的 Web 應用程序所需的工具。其他一些 J2EE 規范和組件向您提供了您帶來更高級的功能:
Enterprise JavaBeans (EJB) 技術:企業組件(或 beans)存在三種形式:
會話 beans:特殊的 Java 類,類似於在 Microsoft Transaction Server 或 MTS 對象控制下運行的 COM 對象。與 MTS 對象一樣,會話 beans 在容器中運行 ―― MTS Executive(就 MTS 對象而言)和 EJB 容器(就會話 bean 而言)。EJB 容器提供諸如聲明性的事務管理、基於角色的安全、分布式環境中的無縫集成以及根據需要激活等服務。會話 bean 又存在兩種形式:
無狀態的:方法調用之間沒有維護狀態,因此您必須提供通過參數來調用某個方法時所需要的全部信息。無狀態會話 bean 的優點在於,容器可以使用任何實例來服務於任何客戶機調用。
有狀態的:方法調用之間的狀態得到保持,以便客戶機總是與特定的實例相關聯。有狀態會話 bean 的優點在於,客戶機可以使用對話模式來與有狀態的會話 bean 交互。當重新創建中間狀態信息的成本所需的代價很大時,這就特別有用。
實體 bean:特殊的 Java 類,它們是存儲在關系數據庫或其他持久存儲中持久數據的對象表示。它們可以封裝數據庫模型中的表,也可以封裝數據模型中表之間的關系。與會話 bean 相似,它們在提供以下服務的容器中運行:聲明性的事務管理、基於角色的安全和分布式環境中的無縫訪問。實體 bean 是共享對象,因此容器還要處理並發控制,並確保底層持久數據保持其 ACID(Atomicity、Consistency、Isolation 和 Durability,即原子性、一致性、隔離性和持久性)屬性。(與會話 bean 不同,實體 bean 是共享對象,因此多個客戶機可以並發地訪問單個實例。)簡而言之,實體 bean 防止您直接訪問底層的持久存儲。無需作出任何應用程序更改,就可以將它們部署到各種不同的持久存儲中。(也就是說,無需改動任何代碼,就可以在部署時將實體 bean 映射到它的持久存儲。)因此,例如,無須更改任何應用程序,就可以將已經映射到 Oracle 或 SQL Server 數據庫的一組實體 bean 重新映射到 DB2。
消息驅動的 bean:充當 JMS 相容的消息中間件的監聽器的特殊 Java 類。JMS 是用於訪問消息隊列的標准 Java API。可以將消息驅動的 bean 配置為指向特定的消息隊列;容器會在消息到達該隊列中時激活它們。有了消息驅動的 bean,您就可以提供在消息到達時調用的應用邏輯。每種 J2EE 1.3 相容的應用服務器都必須提供一個 JMS 實現,不過您也可以使用諸如 WebSphere MQ(以前名為 MQSeries)這樣的流行消息中間件。
Java 連接器體系結構(Java Connector Architecture,JCA):用於訪問許多諸如 CICS、IMS、ERP 和 CRM 這樣的遺留 EIS 系統的標准 API。JCA 把您解放出來,從此不必再學習針對每種 EIS 系統的不同 API。
Java 編程基礎
在深入某些 J2EE 編程概念之前,我們首先向您介紹 Java 編程語言。可以使用 Java 語言來編寫服務器端應用程序以及具有 GUI 的桌面應用程序。本文假定您想要在服務器端使用 Java 語言來補充一個基於 Web 的界面,因此我們將跳過 CUI 編程環境,而是重點關注該平台的非可視化方面。我們首先介紹 Java 軟件開發包(Java Software Development Kit,SDK),然後向您展示如何使用 Java 代碼來編寫歷史悠久的 Hello World 應用程序。然後,我們將深入介紹 Visual Basic 6 和 Java 語言之間的差別。如果您是一個 C/C++ 程序員,可以跳過本節,學習教程“C/C++ 開發人員的 Java 編程”(請參閱 參考資料)。
Java SDK 簡介
Java SDK 是編寫和運行 Java 程序所需的一組命令行工具和包。Java 程序通過即時(Just In Time,JIT)編譯器編譯為平台無關的字節碼,然後該字節碼可以在運行時編譯為本機代碼。其中最重要的工具是 Java 編譯器(javac.exe)和 Java 解釋器(java.exe),後者用於運行 Java 程序。該 SDK 還包括基礎的類(稱為 Java 平台),它們向您提供了開始編寫應用程序所需要的基本功能和 API。
Sun Microsystems 為 Java 平台的 5 個主要版本的各發布了一個 SDK。我們推薦您使用最新的 SDK 版本(Java 1.4.2)來完成本教程的學習。Java SDK 是免費提供的。如果您還沒有,請立即下載(請參閱 參考資料)。
您可以在線參考 Java 2 Standard Edition(J2SE)API 文檔(請參閱 參考資料)。它是一個 HTML 文檔集合,您可以在標准的 Web 浏覽器中浏覽它們。該 API 文檔是必備的參考資料,您或許會頻繁地使用它。
安裝 SDK
在下載 SDK 之後,您需要將它安裝到機器上。安裝過程很簡單。如果安裝程序讓您在典型安裝和自定義安裝之間的選擇,請選擇典型安裝。(僅當您完全知道想要在您的機器上裝載什麼和不裝載什麼,才應該選擇自定義安裝。)安裝過程通常向您提供安裝標准 Java 平台類的源代碼的選擇權。如果機器上有充足的磁盤空間,我們推薦您接受這個選項。這些文件將為您提供一個機會來考察組成 Java 語言和標准 API 的類的實現。它們設計和實現得特別好,您可以從中學到很多知識。
在安裝 SDK 之後,您可能需要配置它,以使它能在您的系統上工作。如何配置 SDK 取決於您的操作系統和所使用的 SDK 版本。該 SDK 包括完整的安裝和配置說明。
第一個 Java 程序
現在您可以編寫自己的第一個 Java 程序 ―― 無處不在的 Hello World 程序。打開文本編輯器,准確地輸入您從清單 1 中看到的源代碼。
清單 1. Hello World 程序
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
Java 語言是區分大小寫的,諸如 class 和 public 這樣的語言關鍵字始終是小寫的。您可以使用任意的大小寫字母組合來表示變量名稱和方法名稱,只要在整個給定的類中一致地使用它們即可。鍵入完成之後,請把代碼保存為一個名為 HelloWorld.java 的文件。您只能選擇這個文件名。Java 源文件使用 .java 擴展名,並且每個 Java 源代碼文件都 必須與您在其中定義的類具有完全相同的名稱。我們已經多次重申了:大小寫是很重要的,因此像 HELLOWORLD.JAVA 和 Helloworld.java 這樣的文件名將導致編譯錯誤。您可以將 HelloWorld.java 保存在機器上任何適當的目錄中。您需要轉到這個目錄來使用命令行工具,因此要確保該目錄便於訪問。
編譯程序
現在您就可以編譯 HelloWorld 程序了。SDK 附帶的 Java 語言編譯器是一個名為 javac.exe 的命令行應用程序。要編譯一個 Java 源代碼文件,您只需將 .java 文件的名稱傳遞給 javac.exe 程序。要編譯這個 HelloWorld 程序,請打開命令提示符,將目錄切換到您保存 HelloWorld.java 文件的位置。然後執行下面這個命令:
javac HelloWorld.java
像 Visual Basic 編譯器一樣,Java 編譯器可能生成任意數目的錯誤。自然,您需要更正所有錯誤,Java 編譯器才會成功地編譯 HelloWorld 程序。編譯成功後將生成一個名為 HelloWorld.class 的類文件。這個文件代表您將在 Java 解釋器中運行的可執行文件。
運行程序
SDK 附帶的 Java 語言解釋器是一個名為 java.exe 的命令行應用程序。要運行 Java 字節碼可執行程序,只需將該 java 程序的名稱傳遞給 java 解釋器。在使用 Java 解釋器時不要指定 .class 擴展名。解釋器僅接受類文件,因此添加 .class 擴展名將產生一個錯誤。要運行這個 HelloWorld 程序,請打開命令提示符,將目錄切換到您編譯 HelloWorld.java 文件的位置。這個字節碼可執行文件 HelloWorld.class 應該就在該目錄中。然後執行下面這個命令:
java HelloWorld
Java 解釋器嘗試執行 HelloWorld 程序的 main() 方法。將 void 作為返回類型的 Java 方法等同於 Visual Basic 中的 Sub 。帶有其他返回類型的方法等同於 Visual Basic 中的 Function 。
Java 解釋器可能會報告運行時錯誤,這通常會終止程序執行。與在 Visual Basic 中一樣,Java 運行時錯誤要比編譯時錯誤更難於調試,不過沒有編譯時錯誤出現得那麼頻繁。在確實發生運行時錯誤時,您可以從容不迫地處理這些錯誤,因為 Java 程序在托管環境中執行,這減少了“失控代碼”造成整個機器緊急停機的可能性。
從 Visual Basic 角度看 Java 101
既然您對 Java 代碼的外觀以及如何編譯並在測試機器上運行有了初步的了解,那麼您應准備深入了解 Java 語言的結構和語法,包括 Java 編程環境和 Java 原始數據類型。由於您熟悉使用 Visual Basic 進行編程,所以您可以通過比較進行學習。我們將就 Java 平台的基礎組件與 Visual Basic 編程框架底層相似組件的關系和區別來討論 Java 平台的基礎組件。如果您是一個 C/C++ 程序員,則可以跳過本節,然後學習教程“C/C++開發人員的 Java 編程”(請參閱 參考資料)。
Visual Basic 執行環境
Visual Basic 是一種高級編程語言;它的目的是使人們可以輕松地開發計算機程序。計算機不能理解高級語言;只能理解低級的機器語言――可以直接在計算機處理器上執行的二進制指令序列。因此,必須將用高級語言編寫的程序轉換成機器語言程序 ―― 可執行程序,然後才能在計算機上執行。不同的計算機使用不同的機器語言。在一台機器上運行的可執行程序將不能在另一台使用不同機器語言的計算機上運行。
將高級編程語言轉換為機器語言可執行程序采用兩種方法:編譯和解釋。編譯會將整個高級語言程序轉換為整個機器語言程序,然後可以全部執行機器語言程序。解釋會將高級語言程序逐行轉換為機器指令;在轉換並執行一行後,才到達下一行。編譯和解釋在邏輯上是等價的,但編譯程序的執行速度一般比解釋程序要快。Visual Basic 程序由名為編譯器的程序編譯成機器語言可執行程序。
Java 執行環境
與 Visual Basic 程序類似,Java 程序也是進行編譯的。但與 Visual Basic 程序不同的是,Java 程序並非被編譯成特定於平台的機器語言。而是被編譯成與平台無關的語言,稱為 字節碼。字節碼與機器語言類似,但設計字節碼的目的並不是在真正的物理計算機上運行。而是由被稱為 Java 虛擬機(Java virtual machine,JVM)的程序運行,Java 虛擬機模擬真實的機器。
簡單地說,JVM 是一個解釋器,它將 Java 字節碼轉換為在底層的、物理機器上執行的真實機器語言指令。更具體的說,術語 Java 虛擬機一般用來指任何執行 Java 類文件的程序。Java 解釋器程序 java.exe 是一個具體的 JVM 實現。
Java 平台使用虛擬機層來保證用 Java 語言編寫的程序是平台無關的。Java 程序一旦編譯成字節碼,就可以在任何擁有 JVM 的系統上運行。這些系統包括 UNIX、Linux、Windows 以及許多其他系統。用其他語言編寫的程序在每個平台上執行時,都必須重新編譯,而 Java 程序只需編譯一次。
數據類型
Java 語言包含兩種不同的數據類型:程序員定義的類(或作為 SDK 或第三方類庫的一部分而可以使用的類)和 Java 運行庫直接理解的“原始”類型( boolean 、 char 、 byte 、 short 、 int 、 long 、 float 和 double )。大多數 Java 原始類型在 Visual Basic 中有等價的類型,而用戶定義的類在很大程度上與 Visual Basic 中的類相似。表 1 列出 Java 語言中原始數據類型和在 Visual Basic 中等價的類型。
表 1. Java 語言原始類型及與其等價的 Visual Basic 類型
Java 原始類型 范圍 Visual Basic 類型 注釋 boolean true,false Boolean 布爾類型的有效值只有 true 和 false。 char 0 - 65535 String (of length 1) Java 語言使用 Unicode 對字符進行編碼。 byte 8 位整數(有符號) Byte ? short 16 位整數(有符號) Integer ? int 32 位整數(有符號) Long ? long 64 位整數(有符號) N/A ? float 32 位浮點數 Single ? double 64 位浮點數 Double ? N/A ? Variant Java 語言沒有 Variant 類型。 N/A ? Date Java 語言沒有原始日期類型。可以 用 Date 類代替。 N/A ? Currency Java 語言沒有原始貨幣類型。可以 用 BigDecimal 類代替。
清單 2 展示了在兩種語言中聲明原始類型的一些示例。
清單 2. 聲明原始類型
Visual Basic Java
Option Explicit // Note that all Java
Dim LetterJ As String, I As Integer, x As Byte // variables must be declared
Dim Point1 As Single, Point2 As Double // before they can be used
Dim IsEmpty As Boolean char letterJ = 'j';
LetterJ = "j" int i = 0;
I = 0 byte x = 12
X = 12 boolean isEmpty = false;
IsEmpty = False float point1 = 1.1F;
Point1 = 1.1 double point2 = 0.0025;
Point2 = 0.0025
運算符
Visual Basic 中的運算符和 Java 語言中的運算符有許多類似性,也有很多重要區別。Java 語言使用的運算符集合與 C 和 C++ 使用的相同。表 2 列出這兩種語言中最常用的運算符。
表 2. Visual Basic 中的運算符和 Java 語言中的運算符
Java 運算符
描述
用法
Visual basic 運算符
注釋
++
增量運算符
++num num++
N/A
這個一元運算符允許增量非浮點數。
--
減量運算符
--numnum--
N/A
這個一元運算符員允許減量非浮點數。
*
/
乘 除
num * num
num / num
*
/
?
/
整除
num/num
\
Java 語言使用相同的運算符進行整除和算術除法。如果操作數是整數,則執行整除運算。
%
取模運算
num % num
Mod
?
+
-
加減
num + num
num - num
+
-
?
+
字符串連接
str + str
&
?
<
<=
小於小於等於
expr < expr
expr <= expr
<
<=
?
>
>=
大於大於等於
expr > expr
expr >= expr
>
>=
?
!=
不等於
expr != expr
<>
?
==
等於(原始類型)
expr == expr
=
?
==
等於(對象)
obj == obj
Is
?
!
邏輯非
!boolean
Not
Visual Basic 對整數按位取反和對布爾表達式邏輯取反采用相同的運算符。而 Java 語言采用不同的運算符。
~
按位取反
~int
Not
?
&
按位與布爾與
int & int
expr & expr
And
?
|
按位或布爾或
int | int
expr | expr
Or
?
^
按位異或布爾異或
int ^ int
expr ^ expr
Xor
?
&&
條件與
if (expr &&expr)...
And
Java 語言對條件與和邏輯布爾與采用不同的運算符。
||
條件或
if (expr || expr) ...
Or
Java 語言對條件或和邏輯布爾或采用不同的運算符。
N/A
模式匹配
str Like pattern
Like
您可以使用 Java String 對象的方法來完成 Visual Basic 運算符的功能。
Visual Basic 函數和子過程與 Java 方法的比較
Visual Basic 允許定義函數和子過程。函數和子過程的主要區別是子過程不返回值,而函數返回值。在 Java 技術中,函數被稱為 方法。Java 語言沒有與 Visual Basic 中的子過程等價的用法。但是,在 Java 語言中,可以使用關鍵字 void 定義不返回值的方法,這種方法大致等價於子過程。只能將 Java 方法聲明位某個類的成員;不能在 Java 類之外定義方法。在清單 3 展示的例子中,一個 Java 方法返回值而另一個不返回值。
清單 3. Java 方法的返回類型
public class MyClass {
// This method doesn't return a value
public void myMethod1(String arg) {
...
}
// This method returns an integer
public int myMethod2(String arg) {
int i;
...
return i ;
}
數組
在 Java 語言中,數組是具有屬性的對象,其中最重要的是 長度 屬性,您可以使用該屬性確定數組的大小。Java 數組的索引值始終從 0 開始,數組的聲明大小包括第 0 個元素。因此,大小為 100 的數組意味著有效索引是從 0 到 99。另外,您還可以將用於表示數組的方括號([ ])與數組類型而非數組名綁定起來。Java 語言允許采用數組字面值,這樣可以將數組初始化為一組預定義的值。清單 4 展示了一些例子。
清單 4. 數組
Visual Basic Java
'An array with 100 integers // An array of 100 integers
Dim a(99) As Integer int[] a = new int[100];
'An array of Strings initialized // An array of Strings initialized
b = Array("Tom","Dick", "Harry") String[] b = {"Tom","Dick", "Harry"};
'Iterating through an array // Iterating through an array of length 100
' of length 100 int [] c = new int [100];
Dim c(99) As Integer for (int i = 0; i <.length; i++) {
For i=0 To UBound(c) c[i] = i;
c(i) = i }
Next
字符串
Visual Basic 使用 String 數據類型來表示字符串。您可通過 String 類的對象來表示 Java 字符串。Visual Basic 和 Java 字符串字面值由一系列加引號的字符表示。在 Java 語言中,可以采用兩種方法創建 String 對象:使用字符串字面量,或使用 構造函數。 String 對象是固定的,這意味著在賦予某個 String 一個初始值後,就不能改變它。換句話說,如果您要更改 String 引用的值,則需要將一個新 String 對象賦值給該引用。由於 Java 字符串是對象,所以可以通過 String 類定義的 接口與這些字符串進行交互。(您可以在本文稍後的 面向對象編程簡介 中了解更多的有關構造函數和接口的信息。) String 類型包含很多接口以及不少有用的方法。
清單 5 演示了一些最常用的方法。請嘗試編譯並運行該例子。記住將源文件命名為 StringTest.java,並且不要忘記文件名的大小寫很重要。
清單 5. Java 語言中的字符串
/*
* The StringTest class simply demonstrates
* how Java Strings are created and how
* String methods can be used to create
* new String objects. Notice that when you
* call a String method like toUpperCase()
* the original String is not modified. To
* actually change the value of the original
* String, you have to assign the new
* String back to the original reference.
*/
public class StringTest {
public static void main(String[] args) {
String str1 = "Hi there";
String str2 = new String("Hi there");
// Display true if str1 and str2 have the value
System.out.println(str1.equals(str2));
// A new uppercase version of str1
System.out.println(str1.toUpperCase());
// A new lowercase version of str2
System.out.println(str1.toLowerCase());
System.out.println(str1.substring(1,4));
// A new version of str1 w/o any trailing whitespace chars
System.out.println(str1.trim());
// Display true if str1 start with "Hi"
System.out.println(str1.startsWith("Hi"));
// Display true if str1 ends with "there"
System.out.println(str1.endsWith("there"));
// Replace all i's with o's
System.out.println(str1.replace('i', 'o'));
}
}
main() 方法
作為應用程序從命令行運行的 Java 類必須定義一個 main() 方法才能運行。在 Java 代碼中, main() 方法遵循嚴格的命名約定。采用下列方式聲明 main() 方法:
public static void main(String[] args)
注:您可以將 public 和 static 修飾符互換位置,可以將 String 數組命名為任何您希望的形式。但是,上述格式是約定俗成的。並非所有的類都需要 main() 方法 ―― 只有從命令行運行的那些類才需要該方法。典型的 Java 應用程序有一個類包含 main() 方法,而其他一些支持類都沒有 main() 方法。
包
諸如 Java 語言之類的面向對象語言非常有利於類的重用。由於大多數程序員使用簡單的描述性名稱(如 Invoice 或 User )對其類進行命名,所以,當您從各種來源重用類時,名稱沖突的可能性很高。Java 語言解決該問題的方法是,讓每個類術語一個 包。您可以同時使用具有相同名稱但屬於不同包中的類。要將類與包關聯起來,必須在類源代碼的第一行代碼進行包聲明。請看下面的例子:
package com.ibm.training;
按照約定,將反向的 Internet 域名(例如, com.yourco.somepackage )作為包名稱的前綴。要使用不同包中的類,有兩種選擇。一種選擇是使用類的完全限定名稱,包括包。清單 6 展示了一個例子。
清單 6. 使用全限定的類名
public class PackDemo1 {
public static void main(String[] args) {
Java.util.Date today = new java.util.Date();
System.out.println("The date is " + today);
}
另一種選擇是在源文件中對在另一個包中的類使用 import 語句。這種情況就不再需要完全限定名,如清單 7 所示。
清單 7. 使用 import 語句
import java.util.Date;
public class PackDemo1 {
public static void main(String[] args) {
Date today = new Date();
System.out.println("The date is " + today);
}
可以使用通配符導入包中的所有類。如果要使用同一包中的幾個類,那麼這種方法很有用,如清單 8 所示。
清單 8. import 語句與通配符一起使用
import java.util.*;
public class PackDemo1 {
public static void main(String[] args) {
Date now = new Date();
System.out.println("The date is " + today);
}
打包以供重用
在 Visual Basic 中,可以編寫代碼並將其構建為一個動態鏈接庫(DLL),在文件系統中,DLL 由擴展名為 .dll 的文件表示。其他程序可以引用 DLL 以使用 DLL 中包含的代碼。Java 語言還允許將類的集合打包到稱為 Java Archive (JAR) 的文件中,以供重用。您可以將類的集合合並到擴展名為 .jar 的文件中,並從其他類中引用 JAR 文件。具有 .jar 擴展名的文件是標准的 zip 文件,可以由 WinZip 或其他壓縮實用程序來操作它們。不過,為方面起見,Java SDK 含了一個名為 jar.exe 的實用程序(在 Windows 平台上),可以使用它來把一組類合並到一個具有 .jar 擴展名的文件中。
在考察使用 jar.exe 實用程序的例子之前,理解包名稱和 Java 平台用於生成類以及在運行時加載它們的目錄結構之間的關系是很重要的。請考慮一個名為 Test的類,它的源代碼在一個名為 Test.java 的文件中。如果將 Test.java 定義為 com.mycompany.test包的一部分,那麼編譯器將為最終的 .class 模塊創建一個目錄樹。該目錄樹就建立在包名稱的基礎上。本例中目錄樹為 com\mycompany\test,並且包名稱中的點號被轉換為目錄邊界。
現在打開一個命令提示符窗口,然後創建一個目錄(例如 c:\javapack)。切換到該目錄( cd javapack)。使用您最喜歡的文本編輯器,將清單 9 中的代碼添加到一個名為 Test.java 的新文件中。
清單 9. 使用包的例子
package com.mycompany.test;
public class Test
{
public static void main(String[] args) {
System.out.println("In test");
}
}
現在使用下面的命令編譯 Test.java。( -d 選項應指向您為這個例子創建的目錄):
java -d c:\javapack Test.java
現在在 c:\javapack 目錄下應該有一個名為 com 的子目錄。事實上,您可以看到編譯所產生的 comTest.class 文件的完全限定名稱是 Test.class。注意包名稱( com.mycompany.test)如何轉換為對應目錄結構(com\mycompany\test),該目錄結構以您使用 -d選項指定的目錄作為根目錄。
下面我們將展示如何打包 Test.class 以方便其他類重用。從 c:\javapack 目錄運行下列命令:
jar -cvf Test.jar com
這個命令將創建一個名為 Test.jar 的文件,它包含 com 子目錄下的所有類。
運行下列命令來使用 Test.jar 文件中的類:
java -classpath Test.jar com.mycompany.test.Test
注意您必須使用全限定類名來從命令行運行該命令,而且還要注意使用 -classpath 選項來指向 Test.jar 文件這個方式。或者,您可以把 Test.jar 文件添加到 CLASSPATH 環境變量中,該變量是分號分隔的 JAR 文件和目錄的列表,Java 編譯器和 JVM 使用這些目錄查找需要加載的類。
其他區別
我們已經了解了 Java 語言和 Visual Basic 的主要語法區別。其他一些區別是:
全局變量:與 Visual Basic 不同,Java 語言不提供任何方法來聲明全局變量(或方法)。
GoTo :盡管 Java 語言將 goto 保留為一個關鍵字,但它沒有與 Visual Basic 使用的類似的 GoTo 語句。
自由放置變量:只要需要,您可以在任何地方聲明 Java 變量。您不需要在程序塊的頂部對變量分組,而在 Visual Basic 中必須這樣。
繼承:Visual Basic 不允許定義擴展其他類功能的類。Java 語言允許定義繼承除類的私有成員外的所有成員的類。這些新類可以擴展它們繼承的類的行為並且替換被繼承成員的行為。(在下一節將了解有關繼承的更多信息。)
面向對象編程簡介
Java 編程語言是面向對象的語言。Visual Basic 具有許多對象特性,但不是嚴格的面向對象語言。本節將討論如何用 Visual Basic 構建一個類,然後討論如何用 Java 語言構建等價的類。
使用類
您可以將 類視為您定義的數據類型。類的變量實例稱為 對象。與其他變量類似,對象具有一個類型、一組屬性和一組操作。對象的類型由從中實例化對象的類表示的。對象的屬性表示其值或狀態。對象的操作是可能的函數集,您可以在對象中調用這些函數來更改其狀態。
請考慮 Visual Basic 的 Integer 基本數據類型,它表示一個整數。您可以使用該類型名稱創建整數實例的變量。每個 Integer 變量都有一個屬性,表示變量存放的整數。每個 Integer 變量還有相同的操作集,您可以使用該操作集來更改變量的狀態(或值)。對 Integer 變量執行的一些操作包括加 (+)、減 (-)、乘 (*)、除 (\) 和取模 (Mod)。
定義 Visual Basic 類
現在,我們來研究您可能要開發自己類型的情形――自己開發的類型是一個 Visual Basic 語言不支持作為基本類型的復雜對象。假定您是為財務機構開發軟件的小組成員,您的工作是開發表示一般銀行帳戶的代碼。一個銀行有很多帳戶,但每個帳戶都有相同的基本屬性和操作的集合。特別是,帳戶包含一個余額和一個 ID 號。清單 10 中的 Visual Basic 代碼定義了帳戶類。它定義了三種操作: Deposit 、 Withdrawal 和 InitAccount (用於初始化余額和帳號)。注意如何通過使用私有變量和您定義的稱為 Balance 的屬性允許該類的用戶獲得余額。
清單 10. 定義 Visual Basic 類
Private theBalance As Currency
Private theAccountNumber As Integer
Public Sub InitAccount (number As Integer, initBal As Currency)
theAccountNumber = number
theBalance = initBal
End Sub
Public Sub Deposit (amount As Currency)
theBalance = theBalance + amount
End Sub
Public Sub Withdrawal (amount As Currency)
theBalance = theBalance - amount
End Sub
Public Property Get Balance() As Currency
Balance = theBalance
End Property
Public Property Get AccountNumber() As Integer
AccountNumber = theAccountNumber
End Property
定義 Java 類
清單 11 用 Java 語言實現 Account 類。
清單 11. Java 語言 Account 類
public class Account {
private double balance;
private int number;
public Account(int number, double balance) {
number = argNumber;
balance = argBalance;
}
public void deposit(double amnt) {
balance += amnt;
}
public void withdrawal (double amnt) {
balance -= amnt;
}
public double getBalance() {
return balance;
}
public int getNumber() {
return number;
}
}
如果您所見,定義 Java 類與定義 Visual Basic 類不同。這兩種語言各自的帳戶類反映了以下主要區別:
在 Java 代碼中,您不需要單獨的方法來初始化 Account 的實例。使用 構造函數即可。如其名稱的含義,您使用它來構建類的實例。構造函數必須與定義它的類具有相同的名稱,而且它可以帶參數。您可以為一個類創建多個構造函數,如果您沒有提供構造函數,則您會自動使用不帶參數的默認構造函數。您可以像清單 11 那樣使用構造函數:
Account myAccount = new Account(12345, 0.00);
與 Visual Basic 不同,Java 語言對屬性沒有特殊規定。按照約定,Java 屬性是私有域,您通常提供一組稱為訪問器(accessor)的方法來訪問包含屬性的域。返回屬性值的方法稱為 getter,設置屬性值的方法稱為 setter。下面是 setter 方法的例子:
public void setIntProperty(int argIntProperty) {intProperty = argIntProperty;}
在 Visual Basic 中,類成員的默認訪問修飾符不是 public (稍後介紹訪問修飾符的更多信息)。
使用對象的帶來的好處
在諸如 Java 語言之類的面向對象語言中使用類和對象會帶來三個主要好處: 封裝、 繼承和 多態 :
封裝(或信息隱藏)是指將對象視作一個“黑盒”;即使用對象時,無須了解(或關心)對象是如何實現的。通過類中定義的方法(運算符)所定義的接口使用對象,可以確保更改類實現而不破壞使用該類對象的任何代碼。
多態是指將不同特性與相同名稱關聯的能力,以及根據上下文選擇正確特性的能力。最常見多態例子是方法重載,您可以定義使用名稱相同的幾種方法,只要這些方法所帶的參數不同即可。
繼承 是指通過編寫擴展現有類的新類來重用代碼。例如,假設您希望編寫新類來表示支票帳戶。因為支票帳戶是一個特殊種類的銀行帳戶,所以可以編寫一個擴展 Account 類(或作為 Account 類的子類)的 CheckingAccount 類。然後, CheckingAccount 類自動獲得 Account 類的狀態和所有運算符(函數)。您只需要添加特定於 CheckingAccount 類的新狀態和運算符即可。例如,您可以添加一個 cashCheck() 函數執行兌現支票帳戶寫的支票的操作。如有必要,還可以更改子類的狀態和行為。例如,可能允許用戶透支其支票帳戶,因此您需要重載透支函數。
深入了解 Java 類
既然您了解面向對象編程框架中類和對象的一般角色,那麼您應深入了解有關 Java 平台的類結構和實現的以下細節:
類成員:類成員總是 域或 方法。域代表數據,而方法代表操作。類可以定義任何數量的成員。
訪問修飾符:使用 訪問修飾符聲明類成員,訪問修飾符指定在定義該成員的類之外對成員的可訪問性。例如,絕對不能訪問聲明為 private 的成員,但可訪問聲明為 public 的成員。
對象:類僅僅是定義而已。代碼中實際使用的是稱為 對象的類的實例。您將了解如何從類創建對象。
構造函數: 構造函數是用於創建對象的特殊運算符。一般來說,如果不能創建類的對象,則這個類就沒有多大用處。構造函數非常重要,因為它們提供創建新類實例的能力。
this 關鍵字 :Java 對象隱含引用自身。了解 this 關鍵字如何引用自身很重要。
類成員
就 成員而言,Java 類是一個定義屬性和操作的獨立代碼模塊。域和方法都是成員的例子。
域是在類的內部聲明的變量。Java 域有兩種變體: 實例變量和 類變量。實例變量與類的每個實例相關,每個實例都有自己的實例變量副本。類變量(用 static 關鍵字聲明)與整個類相關,類與單個類變量共享所有的類實例。例如, BankAccount 中的 balance 域是一個實例域,因為每個 BankAccount 實例有自己的 balance,它獨立於其他每個 Account 對象的 balance。在另一方面,您可以聲明一個 interest 域作為類域,因為每個 BankAccount 對象都采用相同的利率。
方法是類內部的函數。Java 方法有兩種變體: 實例方法和 類方法。每個類實例獲得它自己實例方法的副本,但只有一個類方法的副本,所有類實例都共享它。您可以使用 static 關鍵字聲明類方法。使用實例方法對實例變量進行操作,使用類方法對類變量進行操作。例如, BankAccount 中的 deposit() 方法是一個實例方法,因為每個 BankAccount 都有自己的 balance 域, deposit() 方法對該域進行更改。您可以將 setInterest() 方法聲明為類方法,因為每個 BankAccount 都共享一個 setInterest() 方法可以更改的 interest 域。
清單 12 中的 BankAccount 有五個域: balance (是實例域)、 interest (是類域)。三個成員是方法: deposit() 和 withdraw() 是實例方法, setInterest() 是類方法。注意,您使用對象名稱來訪問實例變量,使用類名稱來訪問類成員。
清單 12. BankAccount 類
public class Account {
public class BankAccount {
private float balance; // an instance field
private static float interest; // a class, or static, field
// an instance method
public void deposit(float amount) {
balance += amount;
}
// an instance method
public void withdraw(float amount) {
balance -= amount;
}
// a class, or static, method
public static void setInterest(float interestRate) {
interest = interestRate;
}
public static void main(String[] args) {
// create a new account object
BankAccount account = new BankAccount();
// deposit $250.00 into the account
account.deposit(250.00F);
// set interest rate for all BankAccount objects
BankAccount.setInterest(5.0F);
}
}
訪問修飾符
與 Visual Basic 類似,Java 語言允許設置類成員的可視性。Java 成員使用 public 修飾符表明可以在類的內部和外部訪問某個成員。Java 使用 private 修飾符表明只能在類的內部訪問該成員。在類的外部是不能訪問私有成員的。
請再次考慮 BankAccount 類。假定您希望使用 BankAccount 對象的程序員通過使用 deposit() 和 withdraw() 方法來更改余額。您要將這些方法聲明為 public ,因此可以在 BankAccount 類的代碼之外調用這些方法。但是,您不希望其他程序員直接更改 balance 域,因此 balance 域的訪問修飾府要采用 private 。
您可能搞不明白默認訪問級別(即沒有使用 public 或 private 修飾符聲明的類成員的訪問級別)是哪個級別。您可能認為默認訪問級別是 public ,即 Visual Basic 中的默認訪問級別。而實際上,Java 語言中的默認訪問級別稱為 包訪問,因為只有同一個包中的類才能訪問這些類成員。如果要將某個成員聲明為包訪問,請不要使用訪問修飾符關鍵字
Java 可以定義一個以上的訪問級別,稱為 protected 。如果希望某個成員可以在子類中訪問,則請使用 protected 修飾符。我們將在 本文後面 討論一些 protected 類成員。
創建對象
如果您研究一下清單 12 中 BankAccount 類的 main() 方法,就會明白下列代碼創建了一個新 BankAccount 對象:
BankAccount account = new BankAccount();
首先,聲明一個類型為 BankAccount 的對象(即變量)。您能會猜到, new 關鍵字留出足夠的內存來創建一個新對象。新對象實際上由以下語句創建的: BankAccount() 。該語句看起來像一個方法調用。然而,清單 12 沒有聲明此名稱的方法,因此您可能想知道這個語句是干什麼的。
實際上,這個語句是一個構造函數調用。沒有構造函數就不能創建 Java 對象,因此,如果您編寫的類沒有構造函數,編譯器就創建一個默認的構造函數。這就是可以調用 BankAccount() 的原因,即使您在 BankAccount 類中沒有顯式編寫構造函數也是如此。
Visual Basic 支持構造函數的概念,方法是允許為每個類定義一個稱為 Class_Initialize 的過程,與 Java 語言不同,它不允許傳遞參數。
Java 構造函數沒有返回類型;所有構造函數都返回定義它的類的新對象。每個 Java 構造函數都必須與聲明它的類有完全相同的名稱。否則,構造函數聲明與方法聲明幾乎一樣。特別是,構造函數可以帶參數,就像 Java 方法一樣。
嚴格地說,構造函數不是一種方法,因為方法是類成員,而構造函數不是。類成員與域和方法一樣,都在子類中繼承。而構造函數是絕對不會被繼承的。
顯式引用
Java 語言使用 this 關鍵字引用當前的對象。您可以使用 this 關鍵字顯式引用當前類中的域、方法和構造函數。
this 關鍵字的常見用法是解決變量范圍問題。例如, BankAccount 類有一個稱為 balance 的字段。我們假定您要編寫一個稱為 setBalance(float balance) 的方法,它設置對象的 balance 域。問題出在 setBalance(float balance) 域的內部,當您引用 balance 時,您實際上引用 balance 參數,而不是 balance 域。您可以通過使用 this 關鍵字顯式引用該域,如清單 13 所示。
清單 13. "this" 關鍵字
public class Account {
public void setBalance(float balance) {
this.balance = balance;
}
繼承
繼承是面向對象編程最重要的優點之一。為了最有效地使用繼承,正確了解繼承非常重要。繼承涉及以下重要概念:
extends 關鍵字 :繼承在聲明類時定義。使用 extends 關鍵字來指定您所編寫的類的超類。
構造函數:構造函數不在子類中繼承,但經常在子類構造函數中調用超類的構造函數。
重載/覆蓋: 重載是編寫名稱相同但參數不同的幾個方法。 覆蓋是指更改子類中繼承的方法的實現。
Object 類 :所有 Java 對象都最終繼承自 Object 類,該類定義每個 Java 一定要具備的基本功能。
接口: 接口是一種行為的描述,但並不實現該行為。
擴展類
在 Visual Basic 中,類不能從任何其他類繼承,但 Java 語言允許單繼承。繼承是重用代碼的一種方式。當類 A 繼承自(或 extends)類 B 時,類 A 就自動繼承類 B 的所有 public 和 protected 成員。如果類 A 與類 B 在同一個包中,則類 A 還繼承所有具有默認(或 包)訪問權的成員。重要的是要注意,子類始終不會繼承它們擴展的類的私有成員。
一旦您擴展了某個類,就可以添加新域和方法,這些新域和方法定義將新類與超類區別開來的屬性和操作。另外,您可以 覆蓋在子類中必須具有不同行為的超類的操作。
定義類時,可以顯式擴展這個類。要擴展類,在該類名後跟一個 extends 關鍵字,然後是要擴展的類的名稱。如果您沒有顯式擴展類,則 Java 編譯器自動擴展類 Object 。這樣,所有 Java 對象最終都是 Object 類的子類。
一個擴展例子
假定您要創建一個新的 CheckingAccount 類。 CheckingAccount 是一個特殊類型的 BankAccount 。換句話說, CheckingAccount 與 BankAccount 有相同的屬性和操作。但是, CheckingAccount 還新增了一個操作――兌現支票。因此,您可以定義 CheckingAccount 類,使它擴展 BankAccount 並添加了一個 cashCheck() 方法,如清單 14 所示。
清單 14. 擴展類
public class CheckingAccount extends BankAccount {
public void cashCheck(float amount) {
withdraw(amount);
}
}
子類構造函數
構造函數不是真正的類成員,因而不對構造函數進行繼承。 BankAccount 構造函數創建 BankAccount 對象,因此,不能在 CheckingAccount 類中使用它來創建 CheckingAccount 對象。但是,可以從超類中使用構造函數來初始化繼承這個超類的子類的一部分。換句話說,您經常需要在子類構造函數中調用超類構造函數來對子類對象進行部分初始化。使用 super 關鍵字,後接代表要調用的超類構造函數的參數的參數化列表就可以做到這一點。如果您要在某個構造函數中使用 super 關鍵字來調用超類的構造函數,則它必須是構造函數體中的第一個語句。
例如,您需要編寫 CheckingAccount 構造函數來初始化 CheckingAccount 對象。您要使用初始余額來創建 CheckingAccount 對象,因此您傳入的是金額。這恰恰與 BankAccount 類中的構造函數非常類似,因此,您使用該構造函數來為您做所有這些工作,如清單 15 所示。
清單 15. 子類構造函數
public class CheckingAccount extends BankAccount {
public CheckingAccount(float balance) {
super(balance);
}
public void cashCheck(float amount) {
withdraw(amount);
}
}
您還可以使用 super 關鍵字來顯式地在子類中引用超類的成員。
重載和覆蓋
Java 語言允許定義幾個同名的方法,只要這些方法的參數不同即可。例如,清單 16 又定義了一個 cashCheck() 方法,該方法帶有兩個參數,一個是要兌現的支票金額,一個是收取服務的費用。這就叫做方法 重載。
清單 16. 方法重載
public void cashCheck(float amount) {
withdraw(amount);
}
public void cashCheck(float amount, float fee) {
withdraw(amount+fee);
}
在創建子類時,您經常要 覆蓋 從超類繼承的方法的行為。例如,假定 CheckingAccount 和 BankAccount 之間的一個不同之處是從 CheckingAccount 提取金額時要收取費用。您需要在 CheckingAccount 類中覆蓋該 withdraw() 方法,以便收取 0.25 美元費用。可以通過使用 super 關鍵字,根據 BankingAccount 的 withdraw() 方法來定義 CheckingAccount 的 withdraw() 方法,如清單 17 所示。
清單 17. 方法覆蓋
public void withdraw(float amount) {
super.withdraw(amount+0.25F);
}
Object 類
Object 類是 Java 類層次結構中的特殊類。所有 Java 類最終都是 Object 類的子類。換句話說,Java 語言支持集中式根類層次結構, Object class 類是該層次結構中的根類。Visual Basic 中也存在相似的概念, Object 變量以後可以實例化為任何類型的類。
由於所有 Java 對象都繼承自 Object 類,所以,可以為任何 Java 對象調用在 Object 中定義的方法,獲得類似的行為。例如,如果 Object 類定義了 toString() 方法,該方法返回代表該對象的 String 對象。您可以為任何 Java 對象調用 toString() 方法,獲得該對象的字符串表示。大多數類定義都覆蓋 toString() 方法,以便它可返回該特定類的特定字符串表示。
在 Java 類層次結構根部的 Object 還有一個含義,即所有對象都能向下強制類型轉換(cast down)到 Object 對象。在 Java 語言中,您可以定義獲得 Object 類的對象的數據結構,這些數據結構可以存放任何 Java 對象。
接口
我已經提過,Java 類只允許單繼承,這意味著 Java 類只能擴展一個類。Java 語言的設計者感到多重繼承太復雜,因此他們改為支持 接口。 接口類似於不能實例化的方法,它定義有方法,但實際上並不實現這些方法。
聲明接口的方法與聲明類相似,不同之處是使用 interface 關鍵字而非 class 關鍵字。接口可以擴展任意數量的超接口。接口內的方法不包含實現。接口方法只是簡單的方法定義;它們沒有方法體。這與 Visual Basic 使用的接口概念相同;接口由屬性和方法聲明組成,沒有代碼。
Account 接口
清單 18 中的代碼展示如何為銀行帳戶編寫定義一組功能的基本 Account 接口。注意,在接口中聲明的方法沒有方法體。
清單 18. Account 接口
public interface Account {
public static final float INTEREST = 0.35F;
public void withdraw(float amount);
public void deposit(float amount);
}
實現接口
Java 類只可擴展一個類,但它可以 實現任意數量的接口。當類實現接口時,它必須實現該接口中定義個每個方法。
清單 19 定義了一個實現 Account 接口的 SavingsAccount 類。由於 Account 接口定義兩個方法―― withdraw(float amount) 和 deposit(float amount) ,所以, SavingsAccount 類必須提供這兩個類的實現。 SavingsAccount 類仍可以擴展另一個類,而且它可以實現任何其他接口,只要它們定義的成員與 Account 接口不同即可。
清單 19. 實現接口
public class SavingsAccount implements Account {
private float balance;
public SavingsAccount(float balance) {
this.balance = balance;
}
public void cashCheck(float amount, float fee) {
withdraw(amount+fee);
}
public void withdraw(float amount) {
balance += balance;
}
public void deposit(float amount) {
balance -= balance;
}
}
小結
到此為止,您已經掌握了 Java 語言的基本組成,並能編寫簡單的 Java 程序。特別是,您應能:
編寫帶有 main() 方法的 Java 類,編譯並運行它。
編寫 Java 接口並編譯它。
為您的類編寫一個或多個構造函數。
編寫擴展另一個類並實現一個或多個接口的類。
通過 new 關鍵字和構造函數調用來創建和使用對象。
您應有足夠的信心來研究和編寫更高級的 Java 代碼。最好使用 Java 平台自帶的類著手進行。獲得使用這種語言經驗的最佳方法是浏覽 API 文檔(請參閱 參考資料),然後使用這些類開始編寫程序。另外,要獲得補充本文的某些選擇資源,請參閱側欄 Honing your skills。