Java反 射

高洛峰
高洛峰原創
2016-10-17 09:35:041617瀏覽

java中java語言的反射機制:

java反射機制在運作狀態中,對於任意一個類別(class檔案),都能知道這個類別的所有屬性和方法;

對於任意一個對象,能夠呼叫它的任一方法與屬性:

這種動態所獲得的資訊以及動態呼叫物件的方法的動能稱為java語言的反射機制。

 

動態獲取類中信息,就是java反射,可以理解對類的解剖。有些應用程式是不能new物件的,但可以動態載入類別取得類別資訊。

Java反 射

 如圖所示,就像類別是物件的描述一樣,Class類別可以對字節碼檔案(.class檔案)物件進行描述。

Java反 射

//早期:new時候,先根據被new的類的名稱找尋該類的字節碼文件,並加載進內存,
//並創建該字節碼文件對象,並接著創建該類字節碼檔案的對應的Person物件。
com.xidian.Person p=new com.xidian.Person();

//現在
String name="com.xidian.Person";
//尋找該文件類文件,並加載進內存,並產生Class對象。
Class clazz=Class.forName(name);
//如何產生該類別的物件呢?
Object obj=clazz.newInstance();

用反射類別載入的方式,從表面上看形式較為複雜但是可擴展性卻更強。原來需要自己在程式檔案手動中建立一個對象,

現在只用在設定檔中寫入字串,就可以建立對應的對象。

 

問題:使用clazz.newInstance()只能使用空參建構函數,要使用參數列表的建構子怎麼辦?

/*
* 取得指定名稱對應類別中的所體現的物件時,
* 而該物件初始化不使用空參建構子該怎麼辦?

* 既然是透過指定的建構子進行物件的初始化,
* 所以應該先得到到該建構子。透過字節碼檔案即可完成。
* 方法是:getConstructor(parameterTypes)

* 在反射中建構器、欄位、方法都是物件。
*/

String name="com.xidian.Person";
Class clazz=Class.forName(name);
//取得到指定的建構子物件
Constructor constructor=clazz.getConstructor(String.class,intint .class); //所有資料型別都可以用字節碼檔.class來描述
//透過該建構器物件的newInstance方法進行物件的初始化。
Object obj=constructor.newInstance("xiaoming",12);

 

 取得指定欄位的值:

//對私有權限檢查。暴力訪問。
field_1.setAccessible(true);

Object obj=clazz.newInstance();
field_1.set(obj,88);

Object o=field_1.get(obj);

Object o=field_1.get(obj);

. );

 


取得函數:

Method method=clazz.getMethod("show",null); //取得無參的方法
Object obj=clazz.newInstance();
method.in
Object obj=clazz.newInstance();
method.in ); 

Method method2=clazz.getMethod("paramMethod",String.class,int.class); //取得有參的方法,方法名稱、參數清單

Object obj2=clazz.newInstance();

method2. invoke(obj2, "小強",89); //invoke:對帶有指定參數的指定物件呼叫由此Method 物件表示的底層方法。

 

反射的應用:

定義一個介面:

package com.xidian;
public interface PCI {
    public void open();
    public void close();
}

定義一個介面實現類別:

package com.xidian;
public class SoundCard implements PCI{
    
    public void open(){
        System.out.println("sound open");
    }
    
    public void close(){
        System.out.println("sound close");
    }

}

定義一個主機板:

package com.xidian;
public class Mainboard {
    
    public void run(){
        System.out.println("main run...");
    }    
    public void usePCI(PCI p){
    if(p!=null){
        p.open();
        p.close();
    }
    }
}

測試度,但是程式碼的可擴充性不好。

如果想增加主機板的設備但是不想修改代碼,改用反射的方式:

不用new來完成,而是只獲取其class文件,在其內部是實現創建對象的動作。

 用反射做設定是應該使用.xml,更精確。而在此我們使用properties物件實作。

 修改主函數碼:

package com.xidian;

public class Test {
    
    public static void main(String[] args){
        Mainboard mb=new Mainboard();
        mb.run();
        mb.usePCI(new SoundCard());      //如果主板需要使用其他设备,必须重新修改代码,传递一个新创建的对象,可扩展性不好。
        
    }
}

設定檔pci.properties:pci1=com.xidian.SoundCard


當擴充裝置的時候,只需要將裝置程式寫好,寫好設定檔,而不需要變更主程式代碼就可使用。

🎜🎜🎜
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn