一、預先需要掌握的知識(java虛拟機)
java虛拟機的方法區:
java虛拟機有一個運作時資料區,這個資料區又被分為方法區,堆區和棧區,我們這裡需要了解的主要是方法區。方法區的主要作用是存儲被裝載的類的類型資訊,當java虛拟機裝載某個類型的時候,需要類裝載器定位相應的class檔案,然後将其讀入到java虛拟機中,緊接着虛拟機提取class中的類型資訊,将這些資訊存儲到方法區中。這些資訊主要包括:
1、這個類型的全限定名
2、這個類型的直接超類的全限定名
3、這個類型是類類型還是接口類型
4、這個類型的通路修飾符
5、任何直接超接口的全限定名的有序清單
6、該類型的常量池
7、字段資訊
8、方法資訊
9、除了常量以外的所有類變量
10、一個到class類的引用
等等(讀者可以參考《深入java虛拟機》這本書的叙述)
Class類:
Class類是一個非常重要的java基礎類,每當裝載一個新的類型的時候,java虛拟機都會在java堆中建立一個對應于新類型的Class執行個體,該執行個體就代表此類型,通過該Class執行個體我們就可以通路該類型的基本資訊。上面說到在方法區中會存儲某個被裝載類的類型資訊,我們就可以通過Class執行個體來通路這些資訊。比如,對于上面說到的資訊Class中都有對應的方法,如下:
1、getName();這個類型的全限定名
2、getSuperClass();這個類型的直接超類的全限定名
3、isInterface();這個類型是類類型還是接口類型
4、getTypeParamters();這個類型的通路修飾符
5、getInterfaces();任何直接超接口的全限定名的有序清單
6、getFields();字段資訊
7、getMethods();方法資訊
等等(讀者可以自己參看jdk幫助文檔,得到更多的資訊)
二、java反射詳解
反射的概念:所謂的反射就是java語言在運作時擁有一項自觀的能力,反射使您的程式代碼能夠得到裝載到JVM中的類的内部資訊,允許您執行程式時才得到需要類的内部資訊,而不是在編寫代碼的時候就必須要知道所需類的内部資訊,這使反射成為建構靈活的應用的主要工具。
反射的常用類和函數:Java反射機制的實作要借助于4個類:Class,Constructor,Field,Method;其中class代表的是類對象,Constructor-類的構造器對象,Field-類的屬性對象,Method-類的方法對象,通過這四個對象我們可以粗略的看到一個類的各個組成部分。其中最核心的就是Class類,它是實作反射的基礎,它包含的方法我們在第一部分已經進行了基本的闡述。應用反射時我們最關心的一般是一個類的構造器、屬性和方法,下面我們主要介紹Class類中針對這三個元素的方法:
1、得到構造器的方法
Constructor getConstructor(Class[] params) -- 獲得使用特殊的參數類型的公共構造函數,
Constructor[] getConstructors() -- 獲得類的所有公共構造函數
Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定參數類型的構造函數(與接入級别無關)
Constructor[] getDeclaredConstructors() -- 獲得類的所有構造函數(與接入級别無關)
2、獲得字段資訊的方法
Field getField(String name) -- 獲得命名的公共字段
Field[] getFields() -- 獲得類的所有公共字段
Field getDeclaredField(String name) -- 獲得類聲明的命名的字段
Field[] getDeclaredFields() -- 獲得類聲明的所有字段
3、獲得方法資訊的方法
Method getMethod(String name, Class[] params) -- 使用特定的參數類型,獲得命名的公共方法
Method[] getMethods() -- 獲得類的所有公共方法
Method getDeclaredMethod(String name, Class[] params) -- 使用特寫的參數類型,獲得類聲明的命名的方法
Method[] getDeclaredMethods() -- 獲得類聲明的所有方法
應用反射的基本步驟:
1、獲得你想操作的類的Class對象;
方法一:Class c=Class.forName("java.lang.String")
方法二:對于基本資料類型可以用形如Class c=int.class或Class c=Integer.TYPE的語句
方法三:Class c=MyClass.class
2、調用Class中的方法得到你想得到的資訊集合,如調用getDeclaredFields()方法得到類的所有屬性;
3、處理第2步中得到的資訊,然後進行你想做的實際操作。
反射執行個體:
下面我将針對類的構造器、屬性和方法分别舉三個例子,向大家示範一下反射的應用過程。
1、構造器
步驟為:通過反射機制得到某個類的構造器,然後調用該構造器建立該類的一個執行個體
package com.test.reflect;
import java.lang.reflect.Constructor;
public class ConstructorDemo {
public ConstructorDemo(){
}
public ConstructorDemo(int a, int b){
System.out.println("a="+a+"b="+b);
}
public static void main(String args[]){
try {
Class cls = Class.forName("com.test.reflect.ConstructorDemo");
System.out.println("class類名稱:"+cls.getName());
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Constructor ct= cls.getConstructor(partypes);
Constructor[] c=cls.getConstructors();
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = ct.newInstance(arglist);
System.out.println("特定構造器對象:"+retobj);
}
catch (Throwable e) {
System.err.println(e);
}
}
}
2、字段屬性
步驟為:通過反射機制得到某個類的某個屬性,然後改變對應于這個類的某個執行個體的該屬性值
package com.test.reflect;
import java.lang.reflect.Field;
public class FieldDemo {
public int a=7;
public int d=9;
private int b=12;
/**
* @param args
*/
public static void main(String[] args) {
try {
Class cls=Class.forName("com.test.reflect.FieldDemo");
//public類型屬性
Field f=cls.getField("a");
System.out.println("特定屬性:"+f);
Field[] fd= cls.getFields();
System.out.println("所有public類型屬性"+fd.length);
//所有級别屬性
Field fld=cls.getDeclaredField("b");
System.out.println("private類型屬性:"+fld);
Field[] fldd= cls.getDeclaredFields();
System.out.println("所有類型屬性"+fldd.length);
} catch (Exception e) {
e.printStackTrace();
}
}
3、方法
步驟為:通過反射機制得到某個類的某個方法,然後調用對應于這個類的某個執行個體的該方法
package com.test.reflect;
import java.lang.reflect.Method;
public class MethodDemo {
public int add(int a, int b){
return a + b;
}
public static void main(String args[]) {
try {
Class cls = Class.forName("com.test.reflect.MethodDemo");
Class partypes[] = new Class[2];
partypes[0] = Integer.TYPE;
partypes[1] = Integer.TYPE;
Method meth = cls.getMethod("add", partypes);
MethodDemo methobj = new MethodDemo();
Object arglist[] = new Object[2];
arglist[0] = new Integer(37);
arglist[1] = new Integer(47);
Object retobj = meth.invoke(methobj, arglist);
Integer retval = (Integer) retobj;
System.out.println(retval.intValue());
} catch (Throwable e) {
System.err.println(e);
}
}
}