面向對象編程簡介
Java 一種面向對象的編程語言。Visual Basic 有很多對象特性,但是它卻不是一種嚴格 的面向對象的語言。在本節,我們將向您介紹如何在 Visual Basic 中構建一個類,然後再 介紹如何在 Java 語言中構建一個等價的類。
類的使用
您可以認為 類就是您要定義的一種數據類型。一個類的變量實例稱為 對象。與其他變量 不同,對象具有類型、一組屬性以及一組操作。對象的類型可以使用該對象實例化時所使用 的類表示。對象的屬性表示該對象的值或狀態。對象的操作是您為了改變對象狀態而調用的 所有函數集。
考慮一下 Visual Basic 的基本數據類型 Integer ,它表示一個整數。您可以使用這種 類型來創建一些變量,這些變量是一個整數的實例。每個 Integer 變量都有一個屬性,這個 屬性表示該變量所持有的是整數數值。每個 Integer 變量都有相同的操作集,這些操作可以 修改變量的狀態(或值)。您可以對 Integer 變量執行的操作包括:加(+)、減(-)、乘 (*)、除(\)以及取模(Mod)。
定義 Visual Basic 類
現在,讓我們假設這樣一種情況:您希望開發一個自己的類型——它可以表示一個復雜的 對象,而在 Visual Basic 語言的基本類型並不支持這種類型。假設您是一名金融系統軟件 開發小組的成員,而您的任務是開發一些代碼來表示一個典型的銀行帳號。雖然一個銀行有 很多種帳號,但是每個帳號都有一些相同的基本屬性和操作。具體來說,每個帳號都有一個 余額和一個 ID 號。清單 10 中給出的 Visual Basic 代碼就定義了一個 account 類。該類 中定義三個操作: 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 類並不相同。這兩 種語言各自的 account 類間的主要區別如下:
在 Java 代碼中,您並不需要使用一個單獨的方法初始化一個 Account 類的實例。您使 用的是 構造函數(constructor)。顧名思義,您可以使用構造函數來構造一個類的實例。 構造函數名必須與定義它的類名相同,而且構造函數可以接收參數。您可以對一個類創建多 個構造函數。如果您沒有提供構造函數,那麼程序可以自動使用一個沒有參數的默認構造函 數。您可以使用下面的方法來使用清單 11 中構造函數:
Account myAccount = new Account(12345, 0.00);
與 Visual Basic 不同,Java 語言對屬性沒有特殊的規定。按照約定,Java 屬性都是私 有的域,您通常會提供一組稱為訪問方法(accessor)的方法對包含這些屬性的域進行訪問 。用來返回屬性值方法稱為 取值方法(getter),用來設置屬性值的方法稱為 賦值方法 (setter)。下面是一個賦值方法的例子:
public void setIntProperty(int argIntProperty) {intProperty = argIntProperty;}
對一個類成員的默認訪問修飾符不是 public ,這與 Visual Basic 不同(後文會進一步 介紹訪問修飾符)。
對象的優點
在諸如 Java 之類的面向對象語言中使用類和對象有三個主要的優點: 封裝 (encapsulation)、 繼承(inheritance)和 多態(polymorphism)。
封裝(或信息隱藏)是指將一個對象看作一個“黑盒”;也就是說,您可以不用知道(或 關心)一個對象是如何實現的就可以使用這個對象。通過類中定義的方法(操作)所定義的 接口來訪問對象可以修改類的實現,而不會破會使用該類對象的任何代碼。
多態是對相同的名字關聯不同特性、而且可以根據上下文選擇正確特性的能力。多態最常 見的例子是方法的重載,此時您可以定義名字相同的多個方法,前提是這些方法使用不同的 參數。
繼承 是指通過編寫對現有的類進行擴展的新類而對代碼進行重用。例如,讓我們假設您 希望編寫一個新類來代表一個支票帳號。由於支票帳號是一種特殊的銀行帳號,因此您可以 編寫一個 CheckingAccount 類(稱為子類)對 Account 類進行擴展。這樣 CheckingAccount 類就可以自動獲得 Account 類中的所有狀態和所有操作(函數)。您只需 要向 CheckingAccount 類中添加一些特殊的新狀態和操作即可。例如,您可以添加一個 cashCheck() 函數來執行為支票帳號存入現金的操作。如果需要,您還可以修改子類繼承的 狀態或行為。例如,一個用戶可能會被允許從她的支票帳號中提款,因此您就可能需要重載 原來的 withdrawal 函數。
深入 Java 類
現在您已經理解了類和對象在面向對象編程框架中的基本角色,也已經准備好專心深入了 解 Java 平台上類的結構和實現的一些特性了:
類成員:類成員通常或者是一個 域,或者是一個 方法。域代表數據,方法代表操作。類 可以定義任意多個成員。
訪問修飾符:您可以使用 訪問修飾符來聲明類成員,這樣可以指定類之外的元素對這些 成員是否可訪問。例如,被聲明為私有的成員在類之外根本不能訪問,但是公開成員可以自 由訪問。
對象:類實際上只是定義而已。您在代碼中真正使用的是類的實例,稱為 對象。後面您 將了解到如何從類創建對象。
構造函數: 構造函數是一個用來創建對象的特殊操作。通常來講,如果您不能對一個類 創建對象,那麼這個類也就沒多少用處了。構造函數非常重要,因為它們提供了創建新類的 實例的能力。
this 關鍵字: 隱式引用 Java 對象本身。您必須理解如何為這種目的而使用 this 關鍵 字,這非常重要。
類成員
Java 類是一個獨立的代碼模塊,其中以 成員的形式定義了很多屬性和操作。域和方法就 是成員的例子。
域是在類中聲明的變量。Java 域有兩種變種: 實例變量和 類變量。實例變量與類的每 個實例有關,每個實例都有自己的一份實例變量的副本。類變量使用 static 關鍵字進行聲 明,與類整體有關,該類會與所有的類實例共享一個類變量。例如, BankAccount 中的 balance 域就是一個實例域,因為每個 BankAccount 實例都有自己的 balance 域,這與其 他所有的 Account 對象的 balance 無關。另外一方面,您可以將一個 interest 域聲明為 一個類域,因為每個 BankAccount 對象都使用相同的利率。
方法是在類中聲明的函數。Java 方法有兩種變體: 實例方法和 類方法。對於實例方法 來說,每個類實例都有自己的實例方法的副本;但是類方法則只有一份副本,所有的類實例 都要共享這個副本。您可以使用 static 關鍵字來聲明類方法。您應該對實例變量使用實例 方法,對類變量使用類方法。例如, BankAccount 類中的 deposit() 方法是一個實例方法 ,因為每個 BankAccount 都有自己的 balance 域, deposit() 方法就會修改該域的值。您 可以將 setInterest() 方法聲明為一個類方法,因為所有的 BankAccount 都共享這個唯一 的 interest 域,而 setInterest() 方法會修改該域的值。
清單 12 中給出的 BankAccount 類有 5 個成員。其中兩個成員是域: 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 修飾符來說明一個成員在類內和類外都可以自由訪問,使用 private 修飾符來說明 一個成員只能在類內使用。私有成員在類外是不能訪問的。
現在讓我們再次考慮一下 BankAccount 類。假設您希望使用 BankAccount 對象的其他程 序員也可以使用 deposit() 和 withdraw() 方法來修改 balance。那麼您就需要將這兩個方 法聲明為 public 類型的,這樣就可以在 BankAccount 類之外的代碼中調用這個類了。然而 ,您並不希望其他程序員直接修改 balance 域,因此就要將 balance 域聲明為 private 類 型的。
您可能會正在考慮默認的訪問權限到底是哪個級別——也就是說,那些您既沒有聲明為 public 也沒有聲明為 private 的類成員的訪問級別是什麼呢?您可能會猜想默認的訪問級 別應該是 public ,在 Visual Baisc 中默認的訪問級別就是 public 。實際上,在 Java 語言中默認的訪問級別稱為 包訪問,因為只有同一個包中的類才有權訪問這些類成員。如果 您希望將一個成員聲明為包訪問的,就不要使用任何訪問修飾符關鍵字。
Java 語言另外定義了一個訪問級別,稱為 受保護級別。當您希望在子類中可以訪問一個 超類的成員時,就可以使用 protected 修飾符。在 本文稍後我們會介紹受保護的類。
創建對象
如果您浏覽一下清單 12 中 BankAccount 類的 main() 方法就會看到創建一個新 BankAccount 對象的代碼,如下所示:
BankAccount account = new BankAccount();
首先,您聲明了一個 BankAccount 類型的對象(也就是一個變量)。正如您可能猜到的 一樣, new 關鍵字會申請足夠的內存來創建一個新對象。新創建的對象實際上是使用這個語 句創建的: BankAccount() 。這條語句很像是一個方法調用。然而,清單 12 並沒有聲明一 個這樣的方法,因此您可能會納悶這條語句到底執行什麼操作。
實際上,這條語句是一個構造函數調用。如果沒有構造函數,您就不能創建 Java 對象, 因此如果您編寫了一個沒有構造函數的類,那麼編譯器就會為您創建一個默認的構造函數。 這就是為什麼即使我們沒有在 BankAccount 類中顯式地編寫一個構造函數,仍然可以可以調 用 BankAccount() 。
Java 類:快速回顧
類成員:Java 類成員有 域和 方法。域名表示數據,方法表示操作。類是一類對象的聲 明,它是使用類成員來定義的。
訪問修飾符:您可以使用 訪問修飾符來限制類成員和構造函數在類外的可見性。大部分 情況下,您會通過將類域聲明為私有的從而實現對數據的封裝,通過編寫一些公開的方法來 定義類的接口。
構造函數:您將 構造函數定義為一種讓其他程序員創建您的類的實例的一種方法。通常 您都會定義構造函數,從而簡化其他程序員創建正確初始化的對象的工作。
Visual Basic 通過讓您為每個類定義一個調用 Class_Initialize 的過程來支持構造函 數的概念,但是它與 Java 語言不同:Visual Basic 不允許您向這個過程傳遞參數。
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 類繼承來的, Object 類定義了每個 Java 對象具有的所有基本功能。
接口: 接口是對行為的描述,但是並不提供實現。
擴展類
在 Visual Basic 中,一個類不能繼承其他類,但是 Java 語言允許單繼承。繼承是一種 代碼重用方法。如果類 A 繼承了類 B(或者說類 A 對類 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 對象都有 balance 初始值,因此您要傳遞一個美元 數量作為參數。這與 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() 方法,這個方法使用要存入的支票數量和使用的費用作為參數。 這稱為方法 重載(overloading)。
清單 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 的費用。您可以定義 CheckingAccount withdraw() 方法,在這個方法中使用 super 關鍵字調用 BankingAccount 的 withdraw() 方法,如清單 17 所示。
清單 17. 方法覆蓋
public void withdraw(float amount) {
super.withdraw(amount+0.25F);
}
Object 類
Object 類是 Java 類層次結構中的一個非常特殊的類。所有的 Java 類最終都是 Object 類的一個子類。換而言之,Java 語言支持一種具有一個中心根類的層次結構,而 Object 類 就是這個類層次的根類。在 Visual Basic 中也有類似的概念: Object 變量可以被實例化 為任何類的對象。
由於所有的 Java 對象都是從 Object 類繼承來的,因此您可以對任何 Java 對象都調用 在 Object 類中定義的方法,而且每個對象的行為都類似。例如, Object 類定義了一個 toString() 方法,該方法會返回一個代表該對象的 String 對象。您可以對任何 Java 對象 調用 toString() 方法,並期望得到該對象的一個字符串表示。大部分定義都會覆蓋 toString() 方法,這樣就可以返回一個表示這個特殊類的一個特殊的字符串。
讓 Object 位於 Java 類層次的根位置的另一種含義是,所有對象都可以強制類型轉換為 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 定義了一個 SavingsAccount 類,它實現了 Account 接口。由於 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 接口並編譯它。
為您的類編寫一個或多個構造函數。
編寫一個擴展另一個類的類,並實現一個或多個接口。
創建並應用使用了新關鍵字和構造函數的調用。
您還應該足夠自信地開始探究更高級的 Java 代碼。一個很好的起點就是 Java 平台類本 身。獲得 Java 語言使用經驗的最佳途徑是浏覽 API 文檔,並開始使用那些類來編寫程序。
使用 Java 技術和 J2EE 的 Web 應用程序體系結構
與您閱讀本文之初相比,現在您已經知道了更多關於 Java 語言的知識,下面應該返回到 支持 Web 的 Windows 客戶機-服務器應用程序這個主題了。將 Java 或 J2EE 應用程序構造 為一個多層的、模塊化的、基於組件的體系結構,這樣在 Web 支持、重用、可維護性和靈活 性方面帶來了許多好處。
典型的 J2EE Web 應用程序體系結構基於模型-視圖-控制器(Model-View-Controller、 MVC)體系結構設計模式(請參閱 圖 1),並且包含以下關鍵元素:
基於瘦客戶機 Web 浏覽器/Java applet 模型的客戶機,它支持從基於浏覽器和基於客戶 機的純 Java 程序對基於服務器的 Web 應用程序進行普遍訪問,從而按需交付應用程序組件 。體系結構合理的 Web 應用程序支持同時用於終端用戶和外部應用程序的多種接口類型。 J2EE 對 Java servlet 和 JavaServer Pages(JSP)的使用,允許用戶從瘦客戶機 Web 浏 覽器和其他設備通過 HTTP 訪問應用程序。您可以使用 HTML、XHTML、XML、JavaScript、 Java applet 以及其他瘦客戶機技術來構建瘦客戶機接口。還可以使用 Java 語言和 J2EE 來構建功能豐富的“瘦客戶機”應用程序,以訪問位於內部網絡/防火牆 之內的基於服務器的應用程序。
提供服務的網絡基礎結構比如 TCP/IP、防火牆、路由器、LDAP 目錄服務器、Web 服務器 和安全 -- 您可以通過開放標准的接口和協議訪問訪問這些服務的功能。
業務邏輯組件,它通過控制事務的執行來強制業務單元的策略和過程,並請求用戶通過用 戶界面提交請求來訪問和更新後端數據源和應用程序。能夠實現應用程序業務邏輯的 Java 和 J2EE 應用程序組件包括 servlet、JavaBean 組件和 Enterprise JavaBean(EJB)組件 。
應用服務器軟件,它為基於 Web 的電子商務應用程序提供平台。它通常包括一個 HTTP 服務器、數據庫和事務服務、會話管理、郵件和群件服務,以及消息服務。諸如 Apache JBoss 和 IBM WebSphere 之類的 J2EE 應用服務器能夠提供這些服務。您需要一個 J2EE 應 用服務器來部署和運行 Web 應用程序的 J2EE 服務器端。
集成中間件和組件,它們允許訪問現有的數據、應用程序組件、數據源,以及在有些情況下 訪問整個應用程序。Java 技術和 J2EE 提供了許多標准組件和技術,用於數據源集成、通過 EJB 組件實現的數據源實體、消息服務以及本機平台服務和組件。Web 應用程序還能夠通過 各種各樣的工具和組件,訪問現有的平台相關的數據和應用程序組件。
後端數據源和現有的非 Java 應用程序和應用程序組件:對於本路標圖來說,這些資產通 常是您不能或不想移植到 Java 或 J2EE,但是又必須與整體 Java 技術或 J2EE 解決方案集 成的 Windows 應用程序組件。新的 Java 或 J2EE 應用程序服務還能夠直接或間接地訪問 Windows 應用程序組件所連接到的關鍵數據源。例如,您可以將 Microsoft SQLServer 客戶 機組件替代為使用 JDBC API 來實現的 Java 數據訪問組件。
Web 應用程序編程環境和開發工具 ,它們提供用於創建、裝配、部署和管理動態和健壯 的電子商務應用程序的服務器端 Java 編程和 J2EE 編程環境。
圖 1. MVC 與 J2EE Web 應用程序
訪問本機 Windows 組件
Java 編程環境為大多數平台無關的常用系統服務提供類和庫,包括 TCP/IP 網絡和套接 字、文件系統資源,以及打印。(我們將在本文後面的 用戶界面考慮因素中討論窗口處理和 用戶界面。)由於您已決定使用 Java 技術來實現應用程序的 Web 支持特性,因此應該使用 對應的支持 Java 的服務和功能來代替任何平台 /Windows 相關的服務和功能。例如,將使 用了 NetBios 或 Windows 網絡的通信服務代替為使用 java.net 包的 TCP/IP 和套接字, 以及將 Windows 文件系統功能代替為 java.io 包中的等價特性。
Java 本機接口(Java Native Interface,JNI)
JNI 提供了用於整合本機 C/C++ 和 Java 代碼的機制。它是一個具有文檔和受支持的 API,JVM 本身就使用該實現來訪問底層的本機平台操作系統服務。這些服務包括大多數平台 上可用的公共功能,比如通信、網絡、應用程序配置、進程管理,以及文件系統。本機平台 服務還可以包括特定平台相關的服務,比如基於 Windows 的網絡、設備管理、打印,以及 COM/DCOM。
如果選擇使用 JNI 來訪問本機 Windows 組件,您就剝奪了自己使用 Java 語言的主要價 值訴求 —— 平台無關性。然而,在某些情況下使用 JNI 是必要的。例如:
您在原型化應用程序的 Java 實現,並且能夠提供瘦客戶機接口和 Java Web 組件作為 Web 應用程序原型的前端。
您在分階段地對應用程序組件向 Java 語言或 J2EE 的移植進行階段測試。作為權宜之計 ,您將剩余的非 Java 組件的服務作為它們當前的 Windows 實現來訪問。
應用程序訪問的服務或數據的接口將是平台相關的(例如 COM/DCOM 組件)。
應用程序訪問的服務或數據是通過某個組件或外部應用程序來提供的,在向 Java 的移植 過程中包括該組件或應用程序是不切實際的。(例如,源代碼不可用是因為另一家公司或合 作伙伴擁有它,因而不允許修改它或再分發它。)
您計劃將應用程序的組件移植到 Java,或者在以後某個時間將它們替代為外部可用的 Java 組件,並且您必須使用本機平台組件。
其他工具和技術
除了 JNI 之外,還有其他幾種工具和技術有助於從 Java 語言中訪問本機 Windows 組件 。與 JNI 一樣,您應該將那些技術的使用限制到以下情況,即您不能使用 Java 語言或 J2EE 實現該集成的本機代碼組件,或者您計劃以後才這樣做。
JNI++ 項目
JNI++ 項目提供了兩個代碼生成實用程序和一個旨在簡化用 C++ 進行 JNDI 編程的核心 C++ 庫。使用僅具有相對簡單的數據結構的本機 C/C++ 類來編寫簡單的 JNI 程序,即這些程序僅訪問字段和使用簡單的訪問方法(accessor)和修改方法 (modifier method),這是相當容易的。但是使用 JNI 來提供對如下這樣的 C/C++ 類的訪 問就更具挑戰了:這些類具有復雜的數據結構、異常處理以及需要從 C/C++ 中回調 Java 代 碼。JNI++ 代碼生成實用程序旨在把從 C/C++ 世界和 Java 語言之間的映射所花的時間減到 最少。JNI++ 生成許多從 Java 語言訪問 C++ 類(或反之)所必需的大量代碼。核心本機代 碼庫為 JVM 和每個運行線程的 JNI 環境提供了簡化的接口。這個庫還包含用於原始 JNI 類 型的包裝類,並且還處理 Java 代碼和 C++ 異常之間的轉換。
Interface Tool for Java
IBM alphaWorks Interface Tool for Java(以前名為 Bridge2Java)允許 Java 程序與 ActivX 對象通信,以便將 ActiveX 對象容易地集成到 Java 環境中。Interface Tool for Java 使用 JNI 和 COM 技術來允許您將 ActiveX 對象 完全當作 Java 對象來處理。您只需運行一個代理生成工具,根據 ActiveX 控件的 typelib 創建 Java 代理。然後您可以使用這些代理來允許 Java 程序與該 ActiveX 對象通信。 Interface Tool for Java 包括的示例展示了 Java 應用程序代碼如何訪問該工具所生成的 那些 Java 代理,從而與各種各樣的 COM 對象交互,包括 Lotus 1-2-3 電子表格、 Microsoft Excel、Microsoft Word、Microsoft Outlook、Microsoft Calendar,以及 Microsoft Internet Explorer。
Codemesh JunC++ion
JunC++ion 允許您混合和匹配 Java 組件與 C++ 組件,以便解決 諸如使 C++ 應用程序支持 Web、將 C++ 客戶機集成到 EJB 環境中、使用 C++ 實現 EJB 組 件以及同時允許 Java 和 C++ 組件使用單個 API 集等問題。
JNIWrapper
JNIWrapper 通過 JNI 提供一個針對平台相關(比如 Windows 和 Linux) 的特性和服務的 Java 接口,這是平台無關的 Java 環境所沒有提供的。有些平台相關的操 作,比如 Windows 下的注冊表項,在 Java 語言中不受支持。為了使用 JNI 來提供這個功 能,您需要實現一個本機庫和一些 Java 類,並與它配合工作,同時在 Java 調試器和本機 端的調試器中測試和調試它。JNIWrapper 提供了用於調用本機庫函數的 Java 庫。使用 JNIWrapper,您可以在 Java 應用程序中訪問本機系統的操作和特性(比如托盤圖標或者定 制的啟動屏幕)。
Jawin 集成項目
Jawin(Java/Win32)是一個免費的、開放源代碼的體系結構,用於 Java 組件和通過 Windows COM 對象或 Windows DLL 來公開的組件之間的互操作。Jawin 允 許 Java 應用程序調用任何基於 COM 或 DLL 的遺留代碼,而不需要編寫任何 JNI 代碼。您 的代碼將能與諸如 Microsoft Office 套件等可編寫腳本的應用程序交互,調用諸如 Microsoft 的基於 COM 的 XML 解析器和工具等可編寫腳本的邏輯組件,以及訪問諸如 Windows 注冊表、安全 API 和事件日志等 Win32 API 特性。Jawin 包括一個用於可編寫腳 本的 COM 組件的代碼生成器。該代碼生成器讀取類型庫,並自動產生從 Java 應用程序調用 該組件所需要的 Java 存根(stub)。
Stryon i-HUB
Stryon Corp. 在其 iHUB 服務器產品中提供了許多技術,允許 Java 和 J2EE 應用程序訪問現有的 Windows .NET 和 COM 應用程序。iHUB 還包括一個 Java 到 COM+ 的橋接中間件,它將 Microsoft ActiveX、DLL 和 COM+ 與運行在支持 Java 的平台上 的 Java 應用程序聯系起來。使用 Java2COM 橋接,Java applet 和應用程序能夠支持現有 的本機代碼。
用戶界面考慮因素
移植用戶界面是從客戶機-服務器轉向基於 Web 的應用程序所面臨的最大挑戰。客戶機- 服務器應用程序通常具有豐富的用戶界面,而這可能難於在基於 Web 的應用程序中重現。簡 單地嘗試將每個屏幕改寫為 Web 頁面通常是徒勞無益的。一個很好的類比是使用逐個短語的 字面翻譯將一本書從一種語言翻譯為另一種語言,這種方法通常會導致無法准確傳達作者原 意的譯文。顯而易見,更好的方法是使用新的語言來表達作者的本意。用戶界面也是如此: 如果使用 Web 設計的最佳實踐而不是使用屏幕到 Web 頁面的簡單映射來設計 Web 界面,這 樣移植到基於 Web 的應用程序的客戶機-服務器應用程序會更好。下面讓我們研究一些可用 的 J2EE 應用程序用戶界面選項。
基於 Web 的界面
大多數基於 Web 的應用程序都能夠利用 Web 浏覽器或基於浏覽器的擴展(比如 MIME 處 理程序和 Java applet)作為它們的界面。這種方法的一個主要優點是,在客戶機需要運行 應用程序的任何內容都包含在浏覽器中,或在應用程序運行時下載到本地,從而使得應用程 序易於管理。具有 Web 浏覽器用戶界面的應用程序可以使用 Java Servlets、JSP 技術、 HTML 以及 JavaScript 來編寫。
Java Server Faces(JSF)是一個相關的規范,它允許 J2EE 提供商為基於 Web 的 J2EE UI 開發提供拖放功能。它還允許廠商開發可供他們的開發工具使用的自定義組件。要看到 JSF 的實際應用,可考察一下 WebSphere Studio 5.11 版中的系列工具。WebSphere Studio 有一個名為 Page Designer 的完全集成的工具,可以使用它通過拖放操作來可視化地開發 HTML 頁面和 JSP 頁面。Page Designer 已實現了 JavaServer Faces 規范,並且允許您將 諸如 HTML 表單元素以及更高級的組件(這些組件允許您將 HTML 表格綁定到後端數據源) 之類的內容拖放到頁面上。
從這裡開始了解 Web 界面設計須知:
useit.com
Jakob Nielsen 是公認的 Web 用戶界面設計專家,他在這個站點上提供了 豐富的信息 -- 包括最佳實踐。您還會找到指向他關於這個主題的書籍和文章的鏈接。
從這裡開始了解關於 JavaServer Faces 的更多信息:
JavaServer Faces 主頁
從 Sun 獲得關於 JSF 的官方信息。
Magical Web Interface Development
這篇文章展示了如何提供基於服務器的強大能力 和構建基於 Web 的用戶界面的靈活性,以使得組件與您的業務對象保持同步。
Developing JSF Applications using WebSphere Studio V5.1.1 -- Part 1
這篇文章 提供了 JSF 開發的實際練習。
JSF Central
這是一個 JavaServer Faces 社區站點,它允許訪問用於開發 JSF 相關 技術的資源。
Applets
applet 是縮微的 Java 應用程序,用戶從網絡上下載它們並在浏覽器中執行。applet 通 常被認為是不受信任的,因為它們匿名地通過網絡發送,並在一個安全的、受限制的 “沙箱(sandbox)”中執行,這個沙箱將它們與當前浏覽器會話之外的 本地系統的所有部分隔離。然而,創建者可以對他們的 applet 簽名,並且浏覽器用戶可以 允許來自受信任的提供商的經過簽名的 applet 擁有特權 —— 比如訪問本地文件系統和其 他資源,這些特權通常與完整的 Java 應用程序聯系在一起。
applet 最初在 Java SDK 的第一個版本中是使用原先的窗口工具包來實現的。Java 2 SDK 引入了允許 applet 使用 Swing 組件而不是使用原先的窗口組件的能力,從而賦予它們 更好的響應能力和平台無關的外觀。
浏覽器“幫助程序”
Java applet 的一種替代技術是浏覽器幫助程序和 MIME 類型處理程序。當基於浏覽器的 GUI 需要訪問文件和資源,而 Web 浏覽器又不能在本地輸出(可視資源)或“播 放”(媒體類型)時,這些技術就可能很有用。這樣的例子包括專用的可視化格式 的應用程序內容,比如地圖、電子表格、字處理文件類型(Adobe Acrobat、Microsoft Word 、Lotus WordPro,等等)、諸如 PostScript 等設備類別相關的文件、諸如視頻、音頻、語 音等多媒體,以及應用程序相關的格式(可以是任意格式)和諸如外部應用程序安裝程序、 軟件清單實用程序、病毒掃描工具、金融或稅務軟件格式等功能。
從這裡開始了解關於浏覽器幫助程序和 MIME 處理程序的更多信息:
Extending the Browser with Plug-ins 這篇文章介紹了插件、客戶機 Java 編程、客戶 機腳本編寫,以及 DOM 和 dHTML。
Web 服務
Web 服務提供了將客戶機-服務器 Windows 應用程序移植到 J2EE 的替代方法。Web 服務 是自包含的、模塊化的應用程序,您使用標准的 Internet 和 XML 技術來構建它們,並描述 和發布到網絡上以供其他程序使用。Web 服務是分布式系統演進過程中的下一步。它們允許 企業使其資產可在全球范圍內通過 Internet 訪問,並且通過開放的 Internet 協議動態地 連接和執行事務。
通過使用諸如 SOAP 這樣的 Web 服務標准,您可以保留當前的 Windows 用戶界面,並使 用 Web 服務來訪問基於 J2EE 的業務邏輯。使用這種方法,你需要使用 J2EE 標准來改寫業 務邏輯,以利用基於服務器的 J2EE 代碼的平台無關性、遠程訪問以及可擴展性,同時保持 Windows 客戶機界面不變,從而最小化對終端用戶的影響。
從這裡開始了解關於 Web 服務的更多信息:
Speed-start Web services
Speed-start Web services 計劃擁有包含 IBM 的最新軟 件開發工具和中間件(試用版)的 DVD、大量的在線教程和文章、實用的研討會和技術簡報 ,以及由 IBM Web 服務專家主持的在線討論論壇以幫助回答您的問題。
Java 客戶機接口
如果需要保持應用程序的豐富外觀和感覺,又要使其能在各種各樣的操作系統平台(比如 Linux)上運行,那麼您應該考慮為 J2EE 應用程序構建一個 Java 客戶機界面。然後應用程 序就能夠利用像 RMI 這樣的標准 API、Web 服務 和 EJB 技術,與 J2EE 服務器代碼以及諸 如文件訪問、網絡、多媒體和圖形窗口功能等系統服務交互。
這種方法要求您或者通過手工過程,或者通過集中管理的自動化分發或共享機制,向用戶 分發應用程序的初始版本和後續更新。(使用 applet、Web 浏覽器插件和 MIME 類型 “幫助程序”的基於“瘦客戶機”浏覽器的界面通 常更容易管理,因為代碼下載是在每次代碼被激活時從 Web 服務器下載的。)
從這裡開始了解關於 Java 客戶機應用程序的更多信息:
" The Java 2 user interface"
這篇 developerWorks文章探討了 JFC/Swing 的各種 特性,包括可插入的外觀和感覺特性、拖放支持、Java 2D 圖形支持、音頻 API、輔助特性 、使用 AWT Robot 的自動化事件,以及媒體支持(包括 3D 圖形、高級圖像處理、Java Media Framework,以及語音) 。
Eclipse.org
Eclipse 是一個基於 Java 的開放和可擴展的 IDE。遵循開放源代碼范型 ,並具有一個提供免費源代碼和全球再分發權的公共公開許可證,Eclipse 平台給開發人員 提供了靈活性和控制能力。
" Using the Eclipse GUI outside the Eclipse Workbench, Part 1: Using JFace and SWT in stand-alone mode"
使用 Standard Widget Toolkit(SWT)和 JFace,您能夠開 發與本機應用程序緊密相似的獨立 Java 應用程序。SWT 是一個窗口工具包,它具有一個與 本機操作系統緊密集成的平台獨立的 API。JFace 是一組建立在 SWT 基礎上的實用工具,用 於使得基於 SWT 編寫 GUI 應用程序代碼更加容易。SWT 和 JFace 都是開放源代碼的 Eclipse 項目的組成部分,可用於將 Java 應用程序與獨立應用程序中的本機平台組件(比 如 ActiveX 控件)集成。標准 Java 用戶界面和窗口系統(Swing)對於開發客戶端應用程 序用戶界面來說是足夠的和經得起考驗的;然而,它缺乏本機應用程序所具有的外觀和風格 ,而 SWT 則直接使用操作系統的本機窗口環境。
" 將 ActiveX 控件集成到 SWT 應用程序 -- 如何將 ActiveX 與 Eclipse 一起使用" 使 用 SWT,您能夠開發感覺和操作起來都像本機應用程序的獨立 Java 應用程序。這篇 developerWorks展示了如何在獨立的 SWT 應用程序中利用和集成 ActiveX 控件。
J2EE 應用程序的部署環境
J2EE 應用程序並不是直接在 Web 服務器器(比如 IIS 或 Apache Web 服務器)上運行 。相反,運行它們的是一個稱為 應用服務器的單獨組件。應用服務器與您選擇的平台上的選 擇的 Web 服務器和平共處。有各種各樣商業化和開放源代碼的應用服務器可供使用。您可以 從以下這些資源了解其中兩種應用服務器的更多信息:
Apache 軟件基金會
Apache 是一個開放源代碼的項目,它提供幾種廣泛使用的 Web 部 署技術。這其中包括一個 Web/HTTP 服務器(Apache Web Server)和一個 servlet 容 器/JSP 處理器(Tomcat)。Apache Web Server 自從 1996 年 4 月以來一直是 Internet 上最流行的 Web 服務器,現在它比其他所有 Web 服務器加起來都還使用得更廣泛。Tomcat 是 Java Servlet 規范和 JavaServer Pages 標准的官方參考實現中所使用的 servlet 容器 。
WebSphere Application Server V5.1 - Express
IBM 提供了一個管理簡單而又動態的 Web 站點的高本益比的現成解決方案,它具有一個簡化的基於 J2EE 的 Web 應用程序服務器 和一個基於 WebSphere Studio 的開發環境。
WebSphere for newcomers
這個路標圖介紹了 IBM WebSphere 系列產品,還提供了幫 助您開始使用 WebSphere 產品來開發和部署 J2EE 解決方案的參考資料。
結束語
我們希望本路標圖為您提供了相關任務和技術的有用概述,從而幫助您將客戶機-服務器 Windows 應用程序移植到 Java 和 J2EE Web 應用程序。祝賀您邁出了走上開放的 Java 編 程之路的第一步。