反射

如果想要對指定名稱的字節碼文件進行加載並獲取其中的內容並調用。怎麼實現呢?這時就使用到了反射技術。


Class類

提供獲取字節碼文件中的內容。比如:名稱,字段,構造函數,一般函數。

該類就可以獲取字節碼文件中的所有內容,那麼反射就是依靠該類完成的。

想要對一一個類文件進行解析,只有獲取到該類的字節碼文件對象即可。


Java 反射機制

在運行狀態中,對於任意一個類(class文件),都能夠知道這個類的所有屬性和方法,
 對於任意一個對象,都能夠調用它的任意一個方法和屬性,這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
 動態獲取類的信息。
 類的剖析,想要剖析必須要有字節碼文件對象,如何獲取字節碼文件對象呢?
 
public class ReflectDemo {


public static void main(String[] args) throws Exception {
getFieldDemo();
}
/*獲取字節碼對象的方式:
* 1 Object類中的getClass()方法
* 想要用這種方式,必須要明確具體的類,並創建對象。

* 2 任何數據類型都具備一個靜態的屬性,class來獲取其對應的Class對象。
* 相對簡單還是要明確用到類中的靜態成員。

* 3 只要通過給定的類的字符串名稱就可以獲取該類,更爲擴展。
* 可用Class類中的方法完成。
* 該方法就是forName
* 這種方式只要有名稱即可,更爲方便擴展性更強

* */
public static void getClassObject_1(){
Person p = new Person();
Class clazz = p.getClass();
Person p1 = new Person();
Class clazz1 = p1.getClass();
System.out.println(clazz==clazz1);
}
public static void getClassObject_2(){
Class clazz = Person.class;

}
public static void getClassObject_3() throws ClassNotFoundException{
String str = "com.reflect.demo.Person";
Class clazz = Class.forName(str);
System.out.println(clazz);
}
public static void createNewObject() throws Exception{
//早期:new,先根據被new的類的名稱找尋該類的字節碼文件,並加載進內存。
//並創建該字節碼文件對象,並接者創建該字節文件的對應的Person
com.reflect.demo.Person p = new com.reflect.demo.Person();

//現在:
String str = "com.reflect.demo.Person";

//找尋該名稱類文件,並加載進內存,併產生Class對象。
Class clazz = Class.forName(str);

//如何產生該類的對象呢?
Object obj = clazz.newInstance();//空參數的構造函數


//當獲取指定名稱對應類中的所體現的對象時,而該對象初始化不使用空參數構造函數怎麼辦?
//既然是通過指定的構造函數進行對象的初始化,所以應該獲取到該構造函數。通過字節碼文件對象即可完成。
//該方法是:getConstructor(paramterTypes)
Constructor con = clazz.getConstructor(String.class,int.class);

//通過該構造器對象的newInstance方法進行對象的初始化。
Object obj1 = con.newInstance("小明",38);
 
}

//獲取字節碼文件中的字段
public static void getFieldDemo() throws Exception{
Class clazz = Class.forName("com.reflect.demo.Person");
Field fie = null;///clazz.getField("age");//只能獲取公有的
fie = clazz.getDeclaredField("age");//只獲取本類,但包含私有。
//對私有字段的訪問取消權限檢查
fie.setAccessible(true);
Object obj = clazz.newInstance();
fie.set(obj, 89);
Object o = fie.get(obj);
System.out.println(o);

}

//獲取指定Class中的公共函數。
public static void getMethodDemo() throws Exception{
Class clazz = Class.forName("com.reflect.demo.Person");
Method[] me = clazz.getMethods();//獲取公有的方法。
me = clazz.getDeclaredMethods();//獲取本類全部方法,只包含私有。
Method method = clazz.getMethod("show", null);//無參數
Object obj = clazz.newInstance();
method.invoke(obj, null);

Method me1 = clazz.getMethod("paraMethod", String.class,int.class);//有參數
me1.invoke(obj, "小強",89);
}


}

運行中想要擴展功能時,想做到不修改源代碼,此時需要兩個東西,一個是接口,一個就是配置文件。

反射練習:

public class ReflectTest {


public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
MainBoard mb = new MainBoard();
mb.run();

File file = new File("prop.properties");
Properties p = new Properties();
FileInputStream in = new FileInputStream(file);
p.load(in);
for(int x = 0;x<p.size();x++){
String str = p.getProperty("pci"+(x+1));
Class clazz = Class.forName(str);
Pci obj = (Pci)clazz.newInstance();//多態
mb.usePci(obj);

}


}


}

public class MainBoard {
public void run(){
System.out.println("主板....運行");
}
public void usePci(Pci p){
p.open();
p.close();
}
}

public interface Pci {
public void open();
public void close();


}

public class SoundCard implements Pci {


public void open() {
    System.out.println("sound open");
}

public void close() {
System.out.println("sound close");
}
}

配置文件信息:

pci1=com.reflect.demo.SoundCard

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章