1. 程式人生 > >Java的動態載入和反射

Java的動態載入和反射

什麼是動態載入?靜態呢?    

    new建立物件的方式稱作為靜態載入,而使用Class.forName("XXX")稱作為動態載入,它們倆本質的區別在於靜態載入的類的源程式在編譯時期載入(必須存在),而動態載入的類在編譯時期可以缺席(源程式不必存在)。

哪些語言是靜態的?哪些是動態的?     

    程式執行時,允許改變程式結構或變數型別,這種語言稱為動態語言。     從這個觀點看,Perl,Python,Ruby是動態語言,而C++,Java,C#不是動態語言。     但是JAVA有著一個非常突出的動態相關機制:Reflection,用在Java身上指的是我們可以於執行時載入、探知、使用編譯期間完全未知的classes。

什麼是反射?

    Reflection 是 Java被視為動態(或準動態)語言的一個關鍵性質。這個機制允許程式在執行時 通過 Reflection APIs 取得任何一個已知名稱的 class 的內部資訊,包括其 modifiers(諸如 public, static 等等)、superclass(例如 Object)、實現的 interfaces,也包括 fields 和 methods 的所有 資訊,並可於執行時改變 fields內容或呼叫 Constructor,methods。          簡而言之,JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性

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

     原來的載入用的好好的,為什麼要使用反射?             

    動態載入最大限度體現了程式的靈活性,降低了類之間的耦合性。方便了框架和其他的使用。或者遊戲更新的時候,不可能將遊戲刪除重新下載,只是下載更新包,然後由遊戲程式執行時動態載入程式碼檔案,得到更新的程式碼編譯,這就用到了反射。反射的目的就是為了擴充套件未知的應用。          反射機制的缺點:對效能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什麼並且它滿足我們的要求。這類操作總是慢於只直接執行相同的操作。

話不多說。進入ctrl + v 貼程式碼模式測試。

為了更好的使用反射,這裡寫了兩個類用來熟悉動態載入。

被載入類

準備了公有的屬性、構造方法、無參方法以及有引數的方法,還有私有的屬性、構造方法、無參方法以及有引數的方法。

package com.example.反射;

public class One {
	
	public int a = 1;
	private int b = 2;
	
	public One() {}
	
	private One(int a) {
		System.out.println("私有構造方法");
	}
	
	public void demo1() {
		System.out.println("呼叫公有方法demo1");
	}
	
	private void demo2() {
		System.out.println("呼叫私有方法demo2");
	}
	
	public void demo3(int a) {
		System.out.println("呼叫有引數的公有方法demo3,引數為"+a);
	}
	
	private void demo4(int b) {
		System.out.println("呼叫有引數的私有方法demo4,引數為"+b);
	}
}

測試

1    首先是對檔案class檔案進行載入,獲得Class檔案物件,獲取Class檔案物件的方法有三種:

     1.Object ——> getClass();      2.任何資料型別(包括基本資料型別)都有一個“靜態”的class屬性      3.通過Class類的靜態方法:forName(String  className)(常用),className是'包名.類名'

Class cl = Class.forName("com.example.反射.One");

2    獲取Class物件的構造方法,通過class物件 cl 呼叫方法獲取構造方法 

    *    這裡需要用到Constructor類,Constructor 提供關於類的單個構造方法的資訊以及對它的訪問許可權

        *    setAccessible(true)方法表示取消java語言訪問檢查,在訪問私有屬性、方法之類時需要使用

			//獲得公有的構造方法
			Constructor con1 = cl.getConstructor();
			System.out.println("呼叫公有"+con1);
			//獲得私有的構造方法
			Constructor con2 = cl.getDeclaredConstructor(int.class);
			con2.setAccessible(true);
			System.out.println("呼叫私有"+con2);

3    建立 Class類物件,也可以說是上面建立的Class檔案物件的物件

    *    建立Class類的物件時,可以通過構造方法建立,也可以通過Class檔案物件建立。

			// 建立類的物件,這裡通過Class檔案物件建立
			Object obj = cl.newInstance();

     *   通過構造方法建立,自定義的構造方法建立物件時可以傳入引數。

			Object obj1 = con1.newInstance();
			Object obj2 = con2.newInstance(5);

4    獲得Class類的屬性,通過Class類的物件 cl 獲得屬性

			//公有屬性
            Field field1 = cl.getField("a");
			System.out.println(field1.get(obj));//得到變數的值
			//私有屬性
			Field field2 = cl.getDeclaredField("b");
			field2.setAccessible(true);//該方法表示取消java語言訪問檢查
			
            //field2.set(obj, 5);//這裡可以給變數重新賦值
			
            System.out.println(field2.get(obj));

 5    獲取Class類的無參方法以及呼叫

    *    呼叫方法時通過方法物件找到Class類的物件

			// 獲取類物件的無參公有方法
			Method m1 = cl.getMethod("demo1");

			//無參私有方法
			Method m2 = cl.getDeclaredMethod("demo2");
			m2.setAccessible(true);//該方法表示取消java語言訪問檢查	
		
			// 呼叫方法
			m1.invoke(obj);
			m2.invoke(obj);

 6    獲取Class類的有參方法以及呼叫

			//有參公有方法
			Method m3 = cl.getMethod("demo3",int.class);
			//有參私有方法
			Method m4 = cl.getDeclaredMethod("demo4", int.class);
			m4.setAccessible(true);
						
			//呼叫方法
			m3.invoke(obj,2);
			m4.invoke(obj, 10);

    Java的反射是框架的基礎,也用於程式的更新,這些都歸功於Java可以實現動態建立物件和編譯。但並不是Java反射是完美的,相反,有利就有弊。反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什麼並且它 滿足我們的要求。這類操作總是慢於只直接執行相同的操作