五月综合缴情婷婷六月,色94色欧美sute亚洲线路二,日韩制服国产精品一区,色噜噜一区二区三区,香港三级午夜理伦三级三

您現(xiàn)在的位置: 365建站網(wǎng) > 365文章 > java反射機(jī)制(原理/應(yīng)用場(chǎng)景/創(chuàng)建對(duì)象)詳解

java反射機(jī)制(原理/應(yīng)用場(chǎng)景/創(chuàng)建對(duì)象)詳解

文章來(lái)源:365jz.com     點(diǎn)擊數(shù):758    更新時(shí)間:2017-11-27 15:26   參與評(píng)論
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意方法和屬性;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱為java語(yǔ)言的反射機(jī)制。
JAVA反射(放射)機(jī)制:“程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語(yǔ)言稱為動(dòng)態(tài)語(yǔ)言”。從這個(gè)觀點(diǎn)看,Perl,Python,Ruby是動(dòng)態(tài)語(yǔ)言,C++,Java,C#不是動(dòng)態(tài)語(yǔ)言。但是JAVA有著一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制:Reflection,用在Java身上指的是我們可以于運(yùn)行時(shí)加載、探知、使用編譯期間完全未知的classes。換句話說,Java程序可以加載一個(gè)運(yùn)行時(shí)才得知名稱的class,獲悉其完整構(gòu)造(但不包括methods定義),并生成其對(duì)象實(shí)體、或?qū)ζ鋐ields設(shè)值、或喚起其methods。

Java的反射機(jī)制是Java特性之一,反射機(jī)制是構(gòu)建框架技術(shù)的基礎(chǔ)所在。靈活掌握J(rèn)ava反射機(jī)制,對(duì)大家以后學(xué)習(xí)框架技術(shù)有很大的幫助。
那么什么是Java的反射呢?
       大家都知道,要讓Java程序能夠運(yùn)行,那么就得讓Java類要被Java虛擬機(jī)加載。Java類如果不被Java虛擬機(jī)加載,是不能正常運(yùn)行的?,F(xiàn)在我們運(yùn)行的所有的程序都是在編譯期的時(shí)候就已經(jīng)知道了你所需要的那個(gè)類的已經(jīng)被加載了。
Java的反射機(jī)制是在編譯并不確定是哪個(gè)類被加載了,而是在程序運(yùn)行的時(shí)候才加載、探知、自審。使用在編譯期并不知道的類。這樣的特點(diǎn)就是反射。
那么Java反射有什么作用呢?
假如我們有兩個(gè)程序員,一個(gè)程序員在寫程序的時(shí)候,需要使用第二個(gè)程序員所寫的類,但第二個(gè)程序員并沒完成他所寫的類。那么第一個(gè)程序員的代碼能否通過編譯呢?這是不能通過編譯的。利用Java反射的機(jī)制,就可以讓第一個(gè)程序員在沒有得到第二個(gè)程序員所寫的類的時(shí)候,來(lái)完成自身代碼的編譯。
Java的反射機(jī)制它知道類的基本結(jié)構(gòu),這種對(duì)Java類結(jié)構(gòu)探知的能力,我們稱為Java類的“自審”。大家都用過Jcreator和eclipse。當(dāng)我們構(gòu)建出一個(gè)對(duì)象的時(shí)候,去調(diào)用該對(duì)象的方法和屬性的時(shí)候。一按點(diǎn),編譯工具就會(huì)自動(dòng)的把該對(duì)象能夠使用的所有的方法和屬性全部都列出來(lái),供用戶進(jìn)行選擇。這就是利用了Java反射的原理,是對(duì)我們創(chuàng)建對(duì)象的探知、自審。
Class類
       要正確使用Java反射機(jī)制就得使用java.lang.Class這個(gè)類。它是Java反射機(jī)制的起源。當(dāng)一個(gè)類被加載以后,Java虛擬機(jī)就會(huì)自動(dòng)產(chǎn)生一個(gè)Class對(duì)象。通過這個(gè)Class對(duì)象我們就能獲得加載到虛擬機(jī)當(dāng)中這個(gè)Class對(duì)象對(duì)應(yīng)的方法、成員以及構(gòu)造方法的聲明和定義等信息。
反射API
        u反射API用于反應(yīng)在當(dāng)前Java虛擬機(jī)中的類、接口或者對(duì)象信息
u功能
—獲取一個(gè)對(duì)象的類信息.
       —獲取一個(gè)類的訪問修飾符、成員、方法、構(gòu)造方法以及超類的信息.
       —檢獲屬于一個(gè)接口的常量和方法聲明.
       —創(chuàng)建一個(gè)直到程序運(yùn)行期間才知道名字的類的實(shí)例.
       —獲取并設(shè)置一個(gè)對(duì)象的成員,甚至這個(gè)成員的名字是
   在程序運(yùn)行期間才知道.
       —檢測(cè)一個(gè)在運(yùn)行期間才知道名字的對(duì)象的方法
    利用Java反射機(jī)制我們可以很靈活的對(duì)已經(jīng)加載到Java虛擬機(jī)當(dāng)中的類信息進(jìn)行檢測(cè)。當(dāng)然這種檢測(cè)在對(duì)運(yùn)行的性能上會(huì)有些減弱,所以什么時(shí)候使用反射,就要靠業(yè)務(wù)的需求、大小,以及經(jīng)驗(yàn)的積累來(lái)決定。

          反射,當(dāng)時(shí)經(jīng)常聽他們說,自己也看過一些資料,也可能在設(shè)計(jì)模式中使用過,但是感覺對(duì)它沒有一個(gè)較深入的了解,這次重新學(xué)習(xí)了一下,感覺還行吧!

           一,先看一下反射的概念:
              主要是指程序可以訪問,檢測(cè)和修改它本身狀態(tài)或行為的一種能力,并能根據(jù)自身行為的狀態(tài)和結(jié)果,調(diào)整或修改應(yīng)用所描述行為的狀態(tài)和相關(guān)的語(yǔ)義。
             反射是java中一種強(qiáng)大的工具,能夠使我們很方便的創(chuàng)建靈活的代碼,這些代碼可以再運(yùn)行時(shí)裝配,無(wú)需在組件之間進(jìn)行源代碼鏈接。但是反射使用不當(dāng)會(huì)成本很高!
             看概念很暈的,繼續(xù)往下看。

      二,反射機(jī)制的作用:
              1,反編譯:.class-->.java
              2,通過反射機(jī)制訪問java對(duì)象的屬性,方法,構(gòu)造方法等;
             這樣好像更容易理解一些,下邊我們具體看怎么實(shí)現(xiàn)這些功能。

      三,在這里先看一下sun為我們提供了那些反射機(jī)制中的類:

java.lang.Class;               
java.lang.reflect.Constructor; java.lang.reflect.Field;       
java.lang.reflect.Method;
java.lang.reflect.Modifier;


            很多反射中的方法,屬性等操作我們可以從這四個(gè)類中查詢。還是哪句話要學(xué)著不斷的查詢API,那才是我們最好的老師。

         四,具體功能實(shí)現(xiàn):
                1,反射機(jī)制獲取類有三種方法,我們來(lái)獲取Employee類型

//第一種方式: 
Classc1 = Class.forName("Employee"); 
//第二種方式: 
//java中每個(gè)類型都有class 屬性. 
Classc2 = Employee.class; 
  
//第三種方式: 
//java語(yǔ)言中任何一個(gè)java對(duì)象都有g(shù)etClass 方法 
Employeee = new Employee(); 
Classc3 = e.getClass(); //c3是運(yùn)行時(shí)類 (e的運(yùn)行時(shí)類是Employee) 



    2,創(chuàng)建對(duì)象:獲取類以后我們來(lái)創(chuàng)建它的對(duì)象,利用newInstance:

Class c =Class.forName("Employee"); 
 
//創(chuàng)建此Class 對(duì)象所表示的類的一個(gè)新實(shí)例 
Objecto = c.newInstance(); //調(diào)用了Employee的無(wú)參數(shù)構(gòu)造方法. 



    3,獲取屬性:分為所有的屬性和指定的屬性:
      a,先看獲取所有的屬性的寫法:

//獲取整個(gè)類 
            Class c = Class.forName("java.lang.Integer"); 
              //獲取所有的屬性? 
            Field[] fs = c.getDeclaredFields(); 
      
                   //定義可變長(zhǎng)的字符串,用來(lái)存儲(chǔ)屬性 
            StringBuffer sb = new StringBuffer(); 
            //通過追加的方法,將每個(gè)屬性拼接到此字符串中 
            //最外邊的public定義 
            sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n"); 
            //里邊的每一個(gè)屬性 
            for(Field field:fs){ 
                sb.append("\t");//空格 
                sb.append(Modifier.toString(field.getModifiers())+" ");//獲得屬性的修飾符,例如public,static等等 
                sb.append(field.getType().getSimpleName() + " ");//屬性的類型的名字 
                sb.append(field.getName()+";\n");//屬性的名字+回車 
            } 
     
            sb.append("}"); 
     
            System.out.println(sb); 


       b,獲取特定的屬性,對(duì)比著傳統(tǒng)的方法來(lái)學(xué)習(xí):

public static void main(String[] args) throws Exception{ 
             
<span style="white-space:pre">  </span>//以前的方式: 
    /*
    User u = new User();
    u.age = 12; //set
    System.out.println(u.age); //get
    */ 
             
    //獲取類 
    Class c = Class.forName("User"); 
    //獲取id屬性 
    Field idF = c.getDeclaredField("id"); 
    //實(shí)例化這個(gè)類賦給o 
    Object o = c.newInstance(); 
    //打破封裝 
    idF.setAccessible(true); //使用反射機(jī)制可以打破封裝性,導(dǎo)致了java對(duì)象的屬性不安全。 
    //給o對(duì)象的id屬性賦值"110" 
    idF.set(o, "110"); //set 
    //get 
    System.out.println(idF.get(o)); 


 4,獲取方法,和構(gòu)造方法,不再詳細(xì)描述,只來(lái)看一下關(guān)鍵字:

方法關(guān)鍵字

含義

getDeclaredMethods()

獲取所有的方法

getReturnType()

獲得方法的放回類型

getParameterTypes()

獲得方法的傳入?yún)?shù)類型

getDeclaredMethod("方法名",參數(shù)類型.class,……)

獲得特定的方法

 

 

構(gòu)造方法關(guān)鍵字

含義

getDeclaredConstructors()

獲取所有的構(gòu)造方法

getDeclaredConstructor(參數(shù)類型.class,……)

獲取特定的構(gòu)造方法

 

 

父類和父接口

含義

getSuperclass()

獲取某類的父類

getInterfaces()

獲取某類實(shí)現(xiàn)的接口

  

         這樣我們就可以獲得類的各種內(nèi)容,進(jìn)行了反編譯。對(duì)于JAVA這種先編譯再運(yùn)行的語(yǔ)言來(lái)說,反射機(jī)制可以使代碼更加靈活,更加容易實(shí)現(xiàn)面向?qū)ο?br />
  五,反射加配置文件,使我們的程序更加靈活:
             在設(shè)計(jì)模式學(xué)習(xí)當(dāng)中,學(xué)習(xí)抽象工廠的時(shí)候就用到了反射來(lái)更加方便的讀取數(shù)據(jù)庫(kù)鏈接字符串等,當(dāng)時(shí)不是太理解,就照著抄了。看一下.NET中的反射+配置文件的使用:
             當(dāng)時(shí)用的配置文件是app.config文件,內(nèi)容是XML格式的,里邊填寫鏈接數(shù)據(jù)庫(kù)的內(nèi)容:

 

      <configuration> 
lt;appSettings> 
<add     key=""  value=""/> 
lt;/appSettings> 
        </configuration> 


反射的寫法:  
 

assembly.load("當(dāng)前程序集的名稱").CreateInstance("當(dāng)前命名空間名稱".要實(shí)例化的類名); 



          這樣的好處是很容易的方便我們變換數(shù)據(jù)庫(kù),例如我們將系統(tǒng)的數(shù)據(jù)庫(kù)從SQL Server升級(jí)到Oracle,那么我們寫兩份D層,在配置文件的內(nèi)容改一下,或者加條件選擇一下即可,帶來(lái)了很大的方便。
           
         當(dāng)然了,JAVA中其實(shí)也是一樣,只不過這里的配置文件為.properties,稱作屬性文件。通過反射讀取里邊的內(nèi)容。這樣代碼是固定的,但是配置文件的內(nèi)容我們可以改,這樣使我們的代碼靈活了很多!

    綜上為,JAVA反射的再次學(xué)習(xí),靈活的運(yùn)用它,能夠使我們的代碼更加靈活,但是它也有它的缺點(diǎn),就是運(yùn)用它會(huì)使我們的軟件的性能降低,復(fù)雜度增加,所以還要我們慎重的使用它。

 

      那么如何利用反射API在運(yùn)行的時(shí)候知道一個(gè)類的信息呢?

 代碼示例:

import java.lang.reflect.Field;

import java.lang.reflect.Method;

import javax.swing.JOptionPane;

/**

  *本類用于測(cè)試反射API,利用用戶輸入類的全路徑,

*找到該類所有的成員方法和成員屬性

  */

public class MyTest {

 

    /**

     *構(gòu)造方法

     */

    public MyTest(){

      

       String classInfo=JOptionPane.showInputDialog(null,"輸入類全路徑");//要求用戶輸入類的全路徑

      

       try {

           Class cla=Class.forName(classInfo);//根據(jù)類的全路徑進(jìn)行類加載,返回該類的Class對(duì)象

          

           Method[] method=cla.getDeclaredMethods();//利用得到的Class對(duì)象的自審,返回方法對(duì)象集合

          

           for(Method me:method){//遍歷該類方法的集合

              System.out.println(me.toString());//打印方法信息

           }

          

           System.out.println("********");

          

           Field[] field=cla.getDeclaredFields();//利用得到的Class對(duì)象的自審,返回屬性對(duì)象集合

           for(Field me:field){ //遍歷該類屬性的集合

              System.out.println(me.toString());//打印屬性信息

           }

       } catch (ClassNotFoundException e) {

           e.printStackTrace();

       }

    }

    public static void main(String[] args) {

       new MyTest();

    }

}

運(yùn)行的時(shí)候,我們輸入javax.swing.JFrame,那么運(yùn)行結(jié)果如下:

 public void javax.swing.JFrame.remove(java.awt.Component)

public void javax.swing.JFrame.update(java.awt.Graphics)

…………

 

********

public static final int javax.swing.JFrame.EXIT_ON_CLOSE

private int javax.swing.JFrame.defaultCloseOperation

 …………

     大家可以發(fā)現(xiàn),類的全路徑是在程序運(yùn)行的時(shí)候,由用戶輸入的。所以虛擬機(jī)事先并不知道所要加載類的信息,這就是利用反射機(jī)制來(lái)對(duì)用戶輸入的類全路徑來(lái)對(duì)類自身的一個(gè)自審。從而探知該類所擁有的方法和屬性。

 通過上面代碼,大家可以知道編譯工具為什么能夠一按點(diǎn)就能列出用戶當(dāng)前對(duì)象的屬性和方法了。它是先獲得用戶輸入對(duì)象的字符串,然后利用反射原理來(lái)對(duì)這樣的類進(jìn)行自審,從而列出該類的方法和屬性。

使用反射機(jī)制的步驟:

u導(dǎo)入java.lang.relfect 

u遵循三個(gè)步驟
第一步是獲得你想操作的類的 java.lang.Class 對(duì)象
第二步是調(diào)用諸如 getDeclaredMethods 的方法
第三步使用 反射API 來(lái)操作這些信息

 獲得Class對(duì)象的方法

 u如果一個(gè)類的實(shí)例已經(jīng)得到,你可以使用

       Class c = 對(duì)象名.getClass(); 

      例: TextField t = new TextField();

              Class c = t.getClass();

              Class s = c.getSuperclass();

u如果你在編譯期知道類的名字,你可以使用如下的方法

Class c = java.awt.Button.class; 
或者

         Class c = Integer.TYPE;

u如果類名在編譯期不知道但是在運(yùn)行期可以獲得你可以使用下面的方法

          Class c = Class.forName(strg);

package

public class MyTest {

    public static void main(String[] args) {

       TestOne  one=null;

       try{

       Class  cla=Class.forName("com.TestOne");//進(jìn)行com.TestOne類加載,返回一個(gè)Class對(duì)象

       System.out.println("********");

       one=(TestOne)cla.newInstance();//產(chǎn)生這個(gè)Class類對(duì)象的一個(gè)實(shí)例,調(diào)用該類無(wú)參的構(gòu)造方法,作用等同于new TestOne()

       }catch(Exception e){

           e.printStackTrace();

       }

       TestOne two=new TestOne();

  System.out.println(one.getClass() == two.getClass());//比較兩個(gè)TestOne對(duì)象的Class對(duì)象是否是同一個(gè)對(duì)象,在這里結(jié)果是true。說明如果兩個(gè)對(duì)象的類型相同,那么它們會(huì)有相同的Class對(duì)象

    }

}

class TestOne{

    static{

       System.out.println("靜態(tài)代碼塊運(yùn)行");

    }

    TestOne(){

       System.out.println("構(gòu)造方法");

    }

}

靜態(tài)代碼塊運(yùn)行

***********

構(gòu)造方法

構(gòu)造方法

Class.forName("com.TestOne")的時(shí)候,實(shí)際上是對(duì)com.TestOne進(jìn)行類加載,這時(shí)候,會(huì)把靜態(tài)屬性、方法以及靜態(tài)代碼塊都加載到內(nèi)存中。所以這時(shí)候會(huì)打印出"靜態(tài)代碼塊運(yùn)行"。但這時(shí)候,對(duì)象卻還沒有產(chǎn)生。所以"構(gòu)造方法"這幾個(gè)字不會(huì)打印。當(dāng)執(zhí)行cla.newInstance()的時(shí)候,就是利用反射機(jī)制將Class對(duì)象生成一個(gè)該類的一個(gè)實(shí)例。這時(shí)候?qū)ο缶彤a(chǎn)生了。所以打印"構(gòu)造方法"。當(dāng)執(zhí)行到TestOne two=new TestOne()語(yǔ)句時(shí),又生成了一個(gè)對(duì)象。但這時(shí)候類已經(jīng)加載完畢,靜態(tài)的東西已經(jīng)加載到內(nèi)存中,而靜態(tài)代碼塊只執(zhí)行一次,所以不用再去加載類,所以只會(huì)打印"構(gòu)造方法",而"靜態(tài)代碼塊運(yùn)行"不會(huì)打印。

 反射機(jī)制不但可以例出該類對(duì)象所擁有的方法和屬性,還可以獲得該類的構(gòu)造方法及通過構(gòu)造方法獲得實(shí)例。也可以動(dòng)態(tài)的調(diào)用這個(gè)實(shí)例的成員方法。

 代碼示例:

 

package reflect;

import java.lang.reflect.Constructor;

/**

 *

 * 本類測(cè)試反射獲得類的構(gòu)造器對(duì)象,

 * 并通過類構(gòu)造器對(duì)象生成該類的實(shí)例

 *

 */

public class ConstructorTest {

     public static void main(String[] args) {

       try {

           //獲得指定字符串類對(duì)象

           Class cla=Class.forName("reflect.Tests");

           //設(shè)置Class對(duì)象數(shù)組,用于指定構(gòu)造方法類型

           Class[] cl=new Class[]{int.class,int.class};

           //獲得Constructor構(gòu)造器對(duì)象。并指定構(gòu)造方法類型

           Constructor con=cla.getConstructor(cl);

          //給傳入?yún)?shù)賦初值

           Object[] x={new Integer(33),new Integer(67)};

           //得到實(shí)例

           Object obj=con.newInstance(x);

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

}

class Tests{

    public Tests(int x,int y){

       System.out.println(x+"    "+y);

    }

}

運(yùn)行的結(jié)果是” 33    67。說明我們已經(jīng)生成了Tests這個(gè)類的一個(gè)對(duì)象。

同樣,也可以通過反射模式,來(lái)執(zhí)行Java類的方法

代碼示例:

package reflect;

import java.lang.reflect.Method;

/**

 *

 * 本類測(cè)試反射獲得類的方法對(duì)象,

 * 并通過類對(duì)象和類方法對(duì)象,運(yùn)行該方法

 *

 */

public class MethodTest {

    public static void main(String[] args) {

       try {

           //獲得窗體類的Class對(duì)象

           Class cla=Class.forName("javax.swing.JFrame");

           //生成窗體類的實(shí)例

           Object obj=cla.newInstance();

       //獲得窗體類的setSize方法對(duì)象,并指定該方法參數(shù)類型為int,int

           Method methodSize=cla.getMethod("setSize"new Class[]{int.class,int.class});

           /*

            * 執(zhí)行setSize()方法,并傳入一個(gè)Object[]數(shù)組對(duì)象,

            * 作為該方法參數(shù),等同于  窗體對(duì)象.setSize(300,300);

            */

           methodSize.invoke(obj, new Object[]{new Integer(300),new Integer(300)});

       //獲得窗體類的setSize方法對(duì)象,并指定該方法參數(shù)類型為boolean

           Method methodVisible=cla.getMethod("setVisible"new Class[]{boolean.class});

           /*

            * 執(zhí)行setVisible()方法,并傳入一個(gè)Object[]數(shù)組對(duì)象,              *作為該方法參數(shù)。 等同于  窗體對(duì)象.setVisible(true);

            */

           methodVisible.invoke(obj, new Object[]{new Boolean(true)});

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

}

反射技術(shù)大量用于Java設(shè)計(jì)模式和框架技術(shù),最常見的設(shè)計(jì)模式就是工廠模式(Factory)和單例模式(Singleton)。

單例模式(Singleton)

       這個(gè)模式主要作用是保證在Java應(yīng)用程序中,一個(gè)類Class只有一個(gè)實(shí)例存在。在很多操作中,比如建立目錄 數(shù)據(jù)庫(kù)連接都需要這樣的單線程操作。這樣做就是為了節(jié)省內(nèi)存空間,保證我們所訪問到的都是同一個(gè)對(duì)象。

       單例模式要求保證唯一,那么怎么樣才能保證唯一性呢?對(duì)了,這就是靜態(tài)變量。單例模式有以下兩種形式:

第一種形式:

package reflect;

public class Singleton {

    /*

     * 注意這是private私有的構(gòu)造方法, 只供內(nèi)部調(diào)用

     * 外部不能通過new的方式來(lái)生成該類的實(shí)例

     */

    private Singleton() {

    }

    /*

     * 在自己內(nèi)部定義自己一個(gè)實(shí)例,是不是很奇怪?

     * 定義一個(gè)靜態(tài)的實(shí)例,保證其唯一性

     */

    private static Singleton instance = new Singleton();

    // 這里提供了一個(gè)供外部訪問本class的靜態(tài)方法,可以直接訪問

    public static Singleton getInstance() {

           return instance;

    }

}

/**

 *測(cè)試單例模式

 */

class SingRun{

    public static void main(String[] args){

       //這樣的調(diào)用不被允許,因?yàn)闃?gòu)造方法是私有的。

       //Singleton x=new Singleton();

       //得到一個(gè)Singleton類實(shí)例

       Singleton x=Singleton.getInstance();

       //得到另一個(gè)Singleton類實(shí)例

       Singleton y=Singleton.getInstance();

       //比較x和y的地址,結(jié)果為true。說明兩次獲得的是同一個(gè)對(duì)象

       System.out.println(x==y);

    }

}

第二種形式:

public class Singleton {

    //先申明該類靜態(tài)對(duì)象

    private static Singleton instance = null;

    //創(chuàng)建一個(gè)靜態(tài)訪問器,獲得該類實(shí)例。加上同步,表示防止兩個(gè)線程同時(shí)進(jìn)行對(duì)象的創(chuàng)建

    public static synchronized Singleton getInstance() {

       //如果為空,則生成一個(gè)該類實(shí)例

       if (instance == null){

           instance = new Singleton();

       }

       return instance;

    }

}

工廠模式(Factory

        工廠模式是我們最常用的模式了,著名的Jive論壇 ,就大量使用了工廠模式,工廠模式在Java程序系統(tǒng)可以說是隨處可見。

為什么工廠模式是如此常用?是因?yàn)楣S模式利用Java反射機(jī)制和Java多態(tài)的特性可以讓我們的程序更加具有靈活性。用工廠模式進(jìn)行大型項(xiàng)目的開發(fā),可以很好的進(jìn)行項(xiàng)目并行開發(fā)。就是一個(gè)程序員和另一個(gè)程序員可以同時(shí)去書寫代碼,而不是一個(gè)程序員等到另一個(gè)程序員寫完以后再去書寫代碼。其中的粘合劑就是接口和配置文件。

之前說利用接口可以將調(diào)用和實(shí)現(xiàn)相分離。

那么這是怎么樣去實(shí)現(xiàn)的呢?工廠模式可以為我們解答。

 我們先來(lái)回顧一下軟件的生命周期,分析、設(shè)計(jì)、編碼、調(diào)試與測(cè)試。其中分析就是指需求分析,就是知道這個(gè)軟件要做成什么樣子,要實(shí)現(xiàn)什么樣的功能。功能知道了,這時(shí)就要設(shè)計(jì)了。設(shè)計(jì)的時(shí)候要考慮到怎么樣高效的實(shí)現(xiàn)這個(gè)項(xiàng)目,如果讓一個(gè)項(xiàng)目團(tuán)隊(duì)并行開發(fā)。這時(shí)候,通常先設(shè)計(jì)接口,把接口給實(shí)現(xiàn)接口的程序員和調(diào)用接口的程序員,在編碼的時(shí)候,兩個(gè)程序員可以互不影響的實(shí)現(xiàn)相應(yīng)的功能,最后通過配置文件進(jìn)行整合。

代碼示例:

/**

 *

 *定義接口

 */

interface InterfaceTest{

    public void getName();//定義獲得名字的方法

}

接口有了,那么得到這個(gè)接口,進(jìn)行實(shí)現(xiàn)編碼的程序員應(yīng)該怎么做呢?對(duì)了,實(shí)現(xiàn)這個(gè)接口,重寫其中定義的方法

 接口實(shí)現(xiàn)方:

/**

 *第一個(gè)程序員書寫的,實(shí)現(xiàn)這個(gè)接口的類

 */

class Test1 implements InterfaceTest{

    /*

     * 根據(jù)業(yè)務(wù),重寫方法

     */

    public void getName() {

       System.out.println("test1");

    }

}

/**

 *第二個(gè)程序員書寫的,實(shí)現(xiàn)這個(gè)接口的類

 */

class Test2 implements InterfaceTest{

    /*

     * 根據(jù)業(yè)務(wù),重寫方法

     */

    public void getName() {

       System.out.println("test2");

    }

}

大家可以發(fā)現(xiàn),當(dāng)接口定義好了以后,不但可以規(guī)范代碼,而且可以讓程序員有條不紊的進(jìn)行功能的實(shí)現(xiàn)。實(shí)現(xiàn)接口的程序員根本不用去管,這個(gè)類要被誰(shuí)去調(diào)用。

 那么怎么能獲得這些程序員定義的對(duì)象呢?在工廠模式里,單獨(dú)定義一個(gè)工廠類來(lái)實(shí)現(xiàn)對(duì)象的生產(chǎn),注意這里返回的接口對(duì)象。

 工廠類,生產(chǎn)接口對(duì)象:

/**

 * 本類為工廠類,用于生成接口對(duì)象

 */

class Factory{

    //創(chuàng)建私有的靜態(tài)的Properties對(duì)象

    private static Properties pro=new Properties();

    //靜態(tài)代碼塊

    static{

       try {

           //加載配置文件

           pro.load(new FileInputStream("file.txt"));

       } catch (Exception e) {

           e.printStackTrace();

       }

    }

    /**

     * 單例模式,保證該類只有一個(gè)對(duì)象

     */

    private static Factory factory=new Factory();

    private Factory(){}

    public static Factory getFactory(){

       return factory;

    }

    /**

     * 本方法為公有方法,用于生產(chǎn)接口對(duì)象

     * @return InterfaceTest接口對(duì)象

     */

    public  InterfaceTest getInterface(){

       InterfaceTest interfaceTest=null;//定義接口對(duì)象

       try {

           //根據(jù)鍵,獲得值,這里的值是類的全路徑

           String classInfo=pro.getProperty("test");

           //利用反射,生成Class對(duì)象

           Class c=Class.forName(classInfo);

           //獲得該Class對(duì)象的實(shí)例

           Object obj=c.newInstance();

           //將Object對(duì)象強(qiáng)轉(zhuǎn)為接口對(duì)象

           interfaceTest=(InterfaceTest)obj;

       } catch (Exception e) {

           e.printStackTrace();

       }

       //返回接口對(duì)象

       return interfaceTest;

    }

}

配置文件內(nèi)容:

test=factory.Test2

通過這個(gè)類,大家可以發(fā)現(xiàn),在調(diào)用的時(shí)候,得到的是個(gè)接口對(duì)象。而一個(gè)接口變量可以指向?qū)崿F(xiàn)了這個(gè)接口的類對(duì)象。在利用反射的時(shí)候,我們并沒有直接把類的全路徑寫出來(lái),而是通過鍵獲得值。這樣的話,就有很大的靈活性,只要改變配置文件里的內(nèi)容,就可以改變我們調(diào)用的接口實(shí)現(xiàn)類,而代碼不需做任何改變。在調(diào)用的時(shí)候,我們也是通過接口調(diào)用,甚至我們可以連這個(gè)接口實(shí)現(xiàn)類的名字都不知道。

調(diào)用方:

public class FactoryTest {

    public static void main(String[] args) {

       //獲得工廠類的實(shí)例

       Factory factory=Factory.getFactory();

       //調(diào)用獲得接口對(duì)象的方法,獲得接口對(duì)象

       InterfaceTest inter=factory.getInterface();

       //調(diào)用接口定義的方法

       inter.getName();

    }

}

 上面的代碼就是調(diào)用方法。大家可以發(fā)現(xiàn),在調(diào)用的時(shí)候,我們根本沒有管這個(gè)接口定義的方法要怎么樣去實(shí)現(xiàn)它,我們只知道這個(gè)接口定義這個(gè)方法起什么作用就行了。上面代碼運(yùn)行結(jié)果要根據(jù)配置文件來(lái)定。如果配置文件里的內(nèi)容是test=factory.Test2。那么表示調(diào)用factory.Test2這個(gè)類里實(shí)現(xiàn)接口的方法,這時(shí)候打印“test2”。如果配置文件里的內(nèi)容是test=factory.Test1。那么表示調(diào)用factory.Test1這個(gè)類里實(shí)現(xiàn)接口的方法,這時(shí)候打印“test1”。

 

反射機(jī)制是框架技術(shù)的原理和核心部分。通過反射機(jī)制我們可以動(dòng)態(tài)的通過改變配置文件(以后是XML文件)的方式來(lái)加載類、調(diào)用類方法,以及使用類屬性。這樣的話,對(duì)于編碼和維護(hù)帶來(lái)相當(dāng)大的便利。在程序進(jìn)行改動(dòng)的時(shí)候,也只會(huì)改動(dòng)相應(yīng)的功能就行了,調(diào)用的方法是不用改的。更不會(huì)一改就改全身。

如對(duì)本文有疑問,請(qǐng)?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會(huì)為你解答!! 點(diǎn)擊進(jìn)入論壇

發(fā)表評(píng)論 (758人查看0條評(píng)論)
請(qǐng)自覺遵守互聯(lián)網(wǎng)相關(guān)的政策法規(guī),嚴(yán)禁發(fā)布色情、暴力、反動(dòng)的言論。
昵稱:
最新評(píng)論
------分隔線----------------------------

其它欄目

· 建站教程
· 365學(xué)習(xí)

業(yè)務(wù)咨詢

· 技術(shù)支持
· 服務(wù)時(shí)間:9:00-18:00
365建站網(wǎng)二維碼

Powered by 365建站網(wǎng) RSS地圖 HTML地圖

copyright © 2013-2024 版權(quán)所有 鄂ICP備17013400號(hào)