這裏所謂的可擴展應用,是指這樣的編程語言或者系統,它可以在不修改現有系統整體或任意一部分功能的情況下,擴展自身的功能。對於傳統的編程語言,比如Cobol、C、C++,如果要爲它們的應用增加新功能,程序員必須重新編輯、編譯和發佈程序,因爲這些語言都是靜態鏈接的語言,不具備動態添加功能的機制(也就是說,生成執行代碼的時候,所有的程序代碼必須事先準備妥當)。Java應用的可擴展能力突破了這些限制。
Java應用的可擴展功能包含了允許動態地定義新的數據類型以及允許用戶插入自己的程序例程的能力。這一切是如何實現的呢?下面我們通過實例來了解具體的實現過程。
普通應用的擴展
在Java中,擴展性源於繼承,具體手段或者是擴展一個類,或者是實現一個接口。Java接口的主要用途就在於此。(Java接口定義了一組方法,但不包含實現。實現某個接口的類必須實現該接口定義的所有方法,因而也就遵循某種確定的行爲模式。)
爲什麼說這個功能對於普通程序來說也很重要呢?如果一個程序是可以動態擴展的,用戶就不必再爲了添加新功能而去修改源程序。這就避免了搞亂原有的代碼,使得用戶能夠專注於自己的那一部分代碼。此外,程序不必爲了引入新功能而重新啓動,這對於那些需要不間斷運行的程序來說無疑是一個福音。
爲進一步瞭解Java程序的動態擴展技術,我們來看一個例子。一家快速增長的保險公司想要用計算機管理它的報價系統。這家公司現有兩個產品:人壽保險(lifecare)和醫療保險(medicare)。根據保額、期限、客戶年齡和保險產品的不同,月保險費用的計算方法也不同。系統應該能夠在不修改原有代碼的情況下,引入保險公司推出的其他產品。爲現有產品設計的類模型如圖一所示。
當一個客戶試圖獲取某種保險產品的報價時,系統創建一個對應該產品類型的對象,調用該對象的calculatePremium()方法,根據指定產品的計算方法計算出保險費用。系統利用一個XML文件(或屬性文件)描述現有產品信息,比如保險產品的名稱和相應的類名稱。XML文件如Listing 1所示。
【Listing 1:描述產品信息的XML文件】
系統從XML文件讀取指定產品的類的全稱,動態地創建對象。然後,系統調用calculatePremium(),根據指定的保額、期限和客戶年齡,按照特定產品的計算邏輯計算出精確的保險費。
現在我們來看看系統如何動態地裝入對象。在把類裝入內存和創建特定產品類型的對象時,系統用到了Java類庫java.lang.Class。Class類的實例或者代表着Java應用中的一個類,或者代表着一個接口。在後臺,Java虛擬機(JVM)常常利用Class類操作Java類;然而,用戶程序也同樣可以通過Class類的實例操作Java類。請參見Listing 2的Class類摘要。
【Listing 2:Class類概要】
public final class java.lang.Class extends
java.lang.Object
{
public static Class forName(String className)
public static Class forName(
String name, boolean initialize, ClassLoader loader)
public Class[] getClasses()
public ClassLoader getClassLoader()
public Class getComponentType()
public Constructor getConstructor(Class[] parameterTypes)
public Constructor[] getConstructors()
public Class[] getDeclaredClasses()
public Constructor getDeclaredConstructor(
Class[] parameterTypes)
public Constructor[] getDeclaredConstructors()
public Field getDeclaredField(String name)
public Field[] getDeclaredFields()
public Method getDeclaredMethod(String name, Class[],
parameterTypes)
public Method[] getDeclaredMethods()
public Class getDeclaringClass()
public Field getField(String name)
public Field[] getFields()
public Class[] getInterfaces()
public Method getMethod(
String name, Class[] parameterTypes)
public Method[] getMethods()
public int getModifiers()
public String getName()
public Package getPackage()
public ProtectionDomain getProtectionDomain()
public URL getResource(String name)
public InputStream getResourceAsStream(String name)
public Object[] getSigners()
public Class getSuperclass()
public boolean isArray()
public boolean isAssignableFrom(Class cls)
public boolean isInstance(Object obj)
public boolean isInterface()
public boolean isPrimitive()
public Object newInstance()
public String toString()
}
在這裏,我們感興趣的主要是forName()方法和newInstance()方法。靜態方法forName()返回和指定類名字關聯的Class對象。它通過類裝入器把類裝入到執行程序。類名字參數可以是classpath中存在的任意一個類。如果不能找到指定類,則forName()方法拋出ClassNotFoundException異常。newInstance()方法爲Class對象代表的類新建一個實例。newInstance()方法也利用類的不帶參數的構造函數創建新對象,因此該類必須有一個不帶參數的構造函數。如果newInstance()方法由於任何原因不能實例化一個類,它將拋出InstantiationException異常;如果不能訪問該類或它的構造函數,則拋出IllegalAccessException異常。Listing 3顯示了Product接口和它的實現:MediCare,LifeCare。
【Listing 3:Product接口及其實現】
// Product.java
// Product接口
package com.test.dynamic;
public interface Product
{
public float calculatePremium(
float face-value,int term, int age);
}
// MediCare.java
// Product的一個實現
package com.test.dynamic;
public class MediCare implements Product
{
public float calculatePremium(
float face-value, int term , int age)
{
float premium;
// 計算保險費
// ......
return premium;
}
}
// LifeCare.java
// Product的一個實現
package com.test.dynamic;
public class LifeCare implements Product
{
public float calculatePremium(
float face-value, int term , int age)
{
float premium;
// 計算保險費(不同的保險產品,計算方法不同)
// .......
return premium;
}
}
當用戶詢問報價時,報價系統根據保險產品的名字裝入並實例化產品類。下面我們用兩個方法實現裝入和調用代碼。GetProductFromName根據指定的產品名字生成合適的產品對象,makeQuote()方法計算保險費。Listing 4顯示了它們的代碼:
【Listing 4:生成產品對象,計算保險費】
public Object GetProductFromName(String productName)
{
// 待裝入對象的類名稱
String className = null;
// 利用XML分析庫org.xml.sax,
// 從XML文件獲取產品的相應類名稱
// ......
// 假定類名字對應正確的產品,例如
// "Com.test.dynamic.MediCare"
try
{
Object o = null;
o = Class.forName(className).newInstance();
}
//catch(ClassNotFoundException e){}
//catch(InstantiationException e){}
//catch(IllegalAccessException e){}
catch( Exception e )
{
e.printStackTrace();
}
return o;
}
// makeQuote方法無返回值
public void makeQuote()
{
String productName;
float faceValue , premium ;
int faceValue, age;
// 從應用的用戶界面獲取所有參數,包括
// 產品名稱、期限、保額、年齡
// (有效的產品可以
Java應用的動態擴展
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.