Java動態類載入

來源:互聯網
上載者:User

Java動態載入類的意義和目的:

Java動態載入類主要是為了不改變主程式碼,通過修改設定檔就可以操作不同的對象執行不同的功能。主要有利於系統的擴充,例如當我要改變一個功能,只需要做一個類,然後編寫相應的功能,通過設定檔就可以使用新的功能,不需要修改系統的任何地方,只需要添加一個類;充分實現了鬆散耦合。滿足了開閉原則(對修改關閉,對添加或刪除開放);

動態載入類設計模式

幾個重要概念

Interface(介面):定義了一堆未實現的方法(即抽象方法);它們的具體實現是由要實現這個介面的類來實現方法的具體功能。

Class.forName(String className): 將一個給定的字串通過forName方法轉換成一個類類型,例如:Class.forName(“Integer”)他就能產生一個Integer類型;通過newInstance()方法可以產生該類的對象。例如ArrayList
arr=(ArrayList)Class.forName(“ArrayList”).newInstance()

就產生了一個ArrayList的對象arr,通過它就可以調用ArrayList類的方法。注意:className對應的字串的類必須有一個無參的構造方法。

Java動態載入類的實現過程(造汽車為例)

1. 建立一個介面(ICarFactory),他有一個未實現的方法makeCar()用於製造汽車。

2. 有兩個類實現了ICarFactory介面,那麼他們也實現了makeCar()方法。

BYDFactroy類----------------makeCar()用於製造BYD,他實現了具體的製造BYD的方法

BMWFactroy類--------------makeCar()用於製造BMW,他實現了具體製造BMW的方法

3. 建立設定檔xml將相應的類名(類全名=包名+類名)寫入相應的位置;

4. 建立主程式類,首先聲明一個ICarFactory類型的變數icf,然後從xml中讀出相應的類名,調用Class.forName(className).instance()得到具體類的執行個體並賦值給icf,最後通過icf調用makeCar()方法,就可以得到一輛造好的汽車。

注意:該實驗用到的JAR包為dom4j-1.6.1.jar,當然你也可以從property裡讀或者直接用java解析xml的類這樣你就不需要這個外部JAR包了。

建立介面

package dynamic.test;

//介面 用於知道汽車 有一個抽象方法makeCar();實現他的類都要實現該方法

public interface ICarFactory {

public void makeCar();//等待實現的造車方法

}

建立兩個實現了介面的類

//建立BYDFactory類,實現了ICarFactory

package dynamic.test;

public class BYDFactory implements ICarFactory {

//實現了ICarFactory的makeCar()方法

public void makeCar() {

System.out.println("BYDFactroy made a BYD for you");

}

}

//建立BMWFactory類,實現了ICarFactory

package dynamic.test;

public class BMWFactory implements ICarFactory {

//實現了ICarFactory的makeCar()方法

public void makeCar() {

System.out.println("BMWFactroy made a BMW for you");

}

}

建立設定檔Factory.xml

<Factory>

<!--相應的造車工廠的類全名,現在的程式可以選dynamic.test.BMWFactory或dynamic.test.BYDFactory -->

<Factroy-Name>dynamic.test.BYDFactory</Factroy-Name>

</Factory>

建立測試程式主類

package dynamic.test;

import java.io.File;

import org.dom4j.Document;

import org.dom4j.DocumentException;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;

public class TestMain {

//測試程式主類;

public static void main(String[] args){

// 聲明介面ICarFactory類型的變數icf

ICarFactory icf=null;

try {

//讀xml可參照讀寫xml的小實驗

File file=new File("lib/Factory.xml");

SAXReader reader=new SAXReader();

Document doc=reader.read(file);

Element root=doc.getRootElement();

String className=root.elementText("Factroy-Name");

//通過className得到相應的類和類執行個體,並將其賦給icf;必須確保className

//對應的類有一個無參構造方法

icf=(ICarFactory) Class.forName(className).newInstance();

//製造相應的汽車

icf.makeCar();

//處理異常

} catch (DocumentException e) {

// TODO Auto-generated catch block

System.out.println("找不到該檔案...");

} catch (InstantiationException e) {

// TODO Auto-generated catch block

System.out.println("執行個體化失敗...");

} catch (IllegalAccessException e) {

// TODO Auto-generated catch block

System.out.println("非法訪問...");

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

System.out.println("找不到該類...");

}

}

}

程式運行結果 (控制台輸出)

BYDFactroy made a BYD for you

修改設定檔Factory.xml,將dynamic.test.BYDFactory改為dynamic.test.BMWFactory

<Factory>

<!--相應的造車工廠的類全名,現在的程式可以選dynamic.test.BMWFactory或dynamic.test.BYDFactory -->

<Factroy-Name>dynamic.test.BMWFactory</Factroy-Name>

</Factory>

再次運行程式觀看結果(控制台輸出)

BMWFactroy made a BMW for you

可以看到兩次運行結果完全不同,並且我們並沒有修改程式的任何一處,只是改了設定檔!這就是動態載入類的優勢,同時它還可以減輕CPU和記憶體的負荷。



以下是引用的一篇文章:

最近在成都寫一個移動增值項目,俺負責後台server端。功能很簡單,手機使用者通過GPRS開啟Socket與伺服器串連,我則根據使用者傳過來的資料做出響應。做過類似項目的兄弟一定都知道,首先需要定義一個類似於MSNP的通訊協議,不過今天的話題是如何把這個系統設計得具有高度的擴充性。由於這個項目本身沒有進行過較為完善的客戶溝通和需求分析,所以以後肯定會有很多功能上的擴充,通訊協議肯定會越來越龐大,而我作為一個不那麼勤快的人,當然不想以後再去修改寫好的程式,所以這個項目是實踐物件導向設計的好機會。

首先定義一個介面來隔離類:

package org.bromon.reflect;

public interface Operator

{

public java.util.List act(java.util.List params)

}

根據設計模式的原理,我們可以為不同的功能編寫不同的類,每個類都繼承Operator介面,用戶端只需要針對Operator介面編程就可以避免很多麻煩。比如這個類:

package org.bromon.reflect.*;

public class Success implements Operator

{

public java.util.List act(java.util.List params)

{

List result=new ArrayList();

result.add(new String(“操作成功”));

return result;

}

}

我們還可以寫其他很多類,但是有個問題,介面是無法執行個體化的,我們必須手動控制具體執行個體化哪個類,這很不爽,如果能夠嚮應用程式傳遞一個參數,讓自己去選擇執行個體化一個類,執行它的act方法,那我們的工作就輕鬆多了。

很幸運,我使用的是Java,只有Java才提供這樣的反射機制,或者說內省機制,可以實現我們的無理要求。編寫一個設定檔emp.properties:

#成功響應

1000=Success

#向客戶發送普通簡訊

2000=Load

#客戶向伺服器發送普通簡訊

3000=Store

檔案中的鍵名是客戶將發給我的訊息頭,客戶發送1000給我,那麼我就執行Success類的act方法,類似的如果發送2000給我,那就執行Load類的act方法,這樣一來系統就完全符合開閉原則了,如果要添加新的功能,完全不需要修改已有代碼,只需要在設定檔中添加對應規則,然後編寫新的類,實現act方法就ok,即使我棄這個項目而去,它將來也可以很好的擴充。這樣的系統具備了非常良好的擴充性和可插入性。

下面這個例子體現了動態載入的功能,程式在執行過程中才知道應該執行個體化哪個類:

package org.bromon.reflect.*;

import java.lang.reflect.*;

public class TestReflect

{

//載入設定檔,查詢訊息頭對應的類名

private String loadProtocal(String header)

{

String result=null;

try

{

Properties prop=new Properties();

FileInputStream fis=new FileInputStream("emp.properties");

prop.load(fis);

result=prop.getProperty(header);

fis.close();

}catch(Exception e)

{

System.out.println(e);

}

return result;

}

//針對訊息作出響應,利用反射匯入對應的類

public String response(String header,String content)

{

String result=null;

String s=null;

try

{

/*

* 匯入屬性檔案emp.properties,查詢header所對應的類的名字

* 通過反射機制動態載入匹配的類,所有的類都被Operator介面隔離

* 可以通過修改屬性檔案、添加新的類(繼承MsgOperator介面)來擴充協議

*/

s="org.bromon.reflect."+this.loadProtocal(header);

//載入類

Class c=Class.forName(s);

//建立類的案例

Operator mo=(Operator)c.newInstance();

//構造參數列表

Class params[]=new Class[1];

params[0]=Class.forName("java.util.List");

//查詢act方法

Method m=c.getMethod("act",params);

Object args[]=new Object[1];

args[0]=content;

//調用方法並且獲得返回

Object returnObject=m.invoke(mo,args);

}catch(Exception e)

{

System.out.println("Handler-response:"+e);

}

return result;

}

public static void main(String args[])

{

TestReflect tr=new TestReflect();

tr.response(args[0],”訊息內容”);

}

}

測試一下:java TestReflect 1000

這個程式是針對Operator編程的,所以無需做任何修改,直接提供Load和Store類,就可以支援2000、3000做參數的調用。

有了這樣的內省機制,可以把介面的作用發揮到極至,設計模式也更能體現出威力

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.