PHP之專案環境變數設定
概述
反射庫(reflection library) 提供了一個非常豐富且精心設計的工具集, 以便編寫能夠動 態操縱 Java 程式碼的程式。這項功能被大量地應用於 JavaBeans 中, 它是 Java元件的體系結構 (有關 JavaBeans 的詳細內容在卷 II中闡述)。使用反射, Java 可以支援 Visual Basic 使用者習慣 使用的工具。特別是在設計或執行中新增新類時, 能夠快速地應用開發工具動態地查詢新添 加類的能力。 能夠分析類能力的程式稱為反射(reflective)。反射機制的功能極其強大,在下面可以看 到, 反射機制可以用來:
•在執行時分析類的能力。
•在執行時檢視物件, 例如, 編寫一個 toString方法供所有類使用。
•實現通用的陣列操作程式碼。
Class類
在程式執行期間,Java執行時系統始終為所有的物件維護一個被稱為執行時的型別標識。 這個資訊跟蹤著每個物件所屬的類。虛擬機器利用執行時型別資訊選擇相應的方法執行。 然而, 可以通過專門的 Java 類訪問這些資訊。儲存這些資訊的類被稱為 Class, 這個名 字很容易讓人混淆。Object 類中的 getClass( ) 方法將會返回一個 Class 型別的例項。
publicstatic void main(String[] args) throws ClassNotFoundException { // TODO Auto-generated method stub Hero hero = new Hero(); Integer h = new Integer(2); String s = new String("面對疾風"); String s2 = "xueren"; //驗證三種獲取Class 物件的方式 Class class1 = Class.forName("com.yunsi.pojo.Hero"); System.out.println(class1.getName()); System.out.println(s.getClass().getName()); System.out.println(Hero.class.getName()); System.out.println(); //一個類中只存在一個Class物件,封裝著這個類的所有資訊 System.out.println(s.getClass().hashCode()); System.out.println(s2.getClass().hashCode()); System.out.println(h.getClass().hashCode()); } } //執行結果如下所示 //com.yunsi.pojo.Hero //java.lang.String //com.yunsi.pojo.Hero //366712642 //366712642 //1829164700
獲取Class類的三種方式
-
物件.getClass
-
Class.forName("String "); //String為某類的報名加類名
-
類.class
注意
獲得 Class類物件的第三種方法非常簡單。如果 T 是任意的 Java型別(或 void關鍵字), T.class 將代表匹配的類物件。例如: Class dl = Random,class; // if you import java.util Gass cl2 = int.class; Class cl3 = Doublet],class; 請注意,一個 Class 物件實際上表示的是一個型別,而這個型別未必一定是一種類。例如, int 不是類,但 int.class 是一個 Class 型別的物件。
註釋: Class 類實際上是一個泛型類。例如, Employee.class 的型別是 Class<Employee>。 沒有說明這個問題的原因是: 它將已經抽象的概念更加複雜化了。在大多數實際問題 中, 可以忽略型別引數, 而使用原始的 Class 類。
鑑於歷史原 getName 方法在應用於陣列型別的時候會返回一個很奇怪的名字:
-
Double[ ] class.getName( ) 返回“ [Ljava.lang.Double;’’
-
int[ ].class.getName( ) 返回“ [I”
還有一個很有用的方法 newlnstance( ),他是Object類中的方法, 可以用來動態地建立一個類的例項例如, e.getClass0.newlnstance(); 建立了一個與 e具有相同類型別的例項。newlnstance方法呼叫預設的構造器(沒有引數的構 造器)初始化新建立的物件。如果這個類沒有預設的構造器, 就會丟擲一個異常_ 將 forName 與 newlnstance 配合起來使用, 可以根據儲存在字串中的類名建立一個物件
String s = "java.util.Random"; Object m = Class.forName(s).newlnstance(); Q 註釋:如果需要以這種方式向希望按名稱建立的類的構造器提供引數, 就不要使用上面 那條語句, 而必須使用 Constructor 類中的 newlnstance 方法。
利用反射分析類的能力
概述:在java.lang.reflect 包中有三個類 Field、Method 和 Constructor 分別用於描述類的域、 方 法和構造器。
-
Field
-
getName() 返回專案的名稱
-
getType(); 返回所描述域所屬型別的Class物件
-
get(Object obj) 檢視物件域
-
getModifiers();
-
static ( isPublic isPrivate isFinal)
-
static toString();
-
-
-
Method
-
getName(); 返回專案的名稱
-
getGenericReturnType() 返回方法的返型別
-
getModifiers(); 返回整數型,用不同的位開關描述public和static這樣的修飾符使用狀況,當沒有這兩個修飾符,則返回值為0
-
static ( isPublic isPrivate isFinal)
-
static toString();
-
-
-
Constructor
-
getName() 返回專案的名稱
-
getModifiers();
-
static ( isPublic isPrivate isFinal)
-
static toString();
-
-
getParameterTypes() 返回一個用於描述引數型別的Class物件的陣列
-
newInstance(); 例項化構造器(Object中的方法)
-
-
Class
-
getFields();
-
getDeclaredFields()
-
getMethods()
-
getDeclaredMethods()
-
getConstructors()
-
getDeclaredConstructors()
-
注意: Class類中的getxxx 和getDeclaredxxx 的區別在於前者返回提供的public修飾的域,方法和構造器陣列,其中包含超類的公有成員;後者返回的是全部域,方法和構造器,其中包括private修飾,但不包括超類的成員
在執行時使用反射分析物件
檢視物件域的關鍵方法是 Field類中的 get 方法。如果 f 是一個 Field型別的物件(例如, 通過 getDeclaredFields 得到的物件),obj 是某個包含 f 域的類的物件,f.get(obj) 將返回一個 物件,其值為 obj 域的當前值。這樣說起來顯得有點抽象,這裡看一看下面這個示例的執行。
Employee harry = new Employee("Harry Hacker", 35000, 10, 1, 1989); Class cl = harry.getClass(); // the class object representing Employee Field f = cl.getDeclaredField("name"): // the name field of the Employee class Object v = f.get(harry); // the value of the name field of the harry object, i.e., the String object "Harry Hacker"
實際上,這段程式碼存在一個問題。由於 name 是一個私有域, 所以 get方法將會丟擲一個 IllegalAccessException。只有利用 get 方法才能得到可訪問域的值。除非擁有訪問許可權,否則 Java 安全機制只允許査看任意物件有哪些域, 而不允許讀取它們的值。 反射機制的預設行為受限於 Java 的訪問控制。然而, 如果一個 Java 程式沒有受到安全管理器的控制, 就可以覆蓋訪問控制。 為了達到這個目的, 需要呼叫 Field、Method 或 Constructor 物件的 setAccessible 方法。例如, f.setAtcessible(true); // now OK to call f.get(harry); setAccessible方法是 AccessibleObject 類中的一個方法, 它是 Field、 Method 和 Constructor 類的公共超類。這個特性是為除錯、持久儲存和相似機制提供的;當然,可以獲得就可以設定。呼叫 f.set(obj,value) 可以將 obj 物件的 f 域設定成新值。
呼叫任意方法
在 Method 類中有一個 invoke 方法, 它允許呼叫包裝在當前 Method 物件中 的方法。invoke 方法的簽名是: Object invoke(Object obj, Object... args) 第一個引數是隱式引數, 其餘的物件提供了顯式引數(在 Java SE 5.0 以前的版本中,必須傳遞一個物件陣列, 如果沒有顯式引數就傳遞一個 null)。 對於靜態方法,第一個引數可以被忽略, 即可以將它設定為 null。
invoke方法的引數,一個是Object型別,也就是呼叫該方法的物件,第二個引數是一個可變引數型別,呼叫者是Method的物件