在運行時判斷任意一個對象所屬的類
在運行時構造任意一個類的對象
在運行時判斷任意一個類所具有的成員變量和方法
在運行時調用任意一個對象的方法
Reflection是java被視爲動態(或準動態)語言的一個關鍵性質。這個機制允許程序運行時透過Reflection APIs取得任何一個已知名稱的class的內部信息,包括其modifiers(修飾符,諸如public,static等等),superclass(父類,例如Object),實現之interfaces(接口,例如Serializable),也包括fields(成員變量)和methods(方法)的所有信息,並可於運行時修改fields內容或調用methods。
通過反射可以去改變一個私有方法,一個私有成員變量(打破類的包裝機制)
程序運行時,允許改變程序結構或變量類型,這種語言稱爲動態語言:Perl,Python,Rudy是動態語言,C++,java,C#不是動態語言。(如圖,javaScript是動態語言)
儘管java不是動態語言,但卻有個非常突出的動態相關機制:反射,意思是指我們可以在運行時加載,探知,使用編譯期間完全未知的classes。(即java可以加載一個運行時才知道其名稱的類,獲悉其完整構造(不包括methods定義,只能得到方法聲明),並生成其對象實體,或對其fields設值,或喚起其methods)。這種看透class的能力稱爲introspection。
java的反射機制,需要使用java.lang.reflect包:
-Class類:代表一個類
-Fields類:類的成員變量(類屬性)
-Method類:代表類的方法
-Constructor類:類的構造方法
-Array類:提供了動態創建數組,以及訪問數組的元素的靜態方法
反射時,前面四個類是一定會用到的
這個方法可以獲得所有方法描述。類似的有getDeclaredFields();
例子DumpMethod.java:讀取命令行參數指定的類名,然後打印這個類所具有的方法信息。
package com.wws.reflect;
import java.lang.reflect.Method;
public class DumpMethod
{
public static void main(String[] args) throws Exception
{
//獲得String的類
Class<?> classType =Class.forName("java.lang.String");
//獲得並返回類的所有方法
Method[] methods =classType.getDeclaredMethods();
for(Method method:methods)
{
System.out.println(method);
}
}
}
結果:
改爲獲取傳入實體的類方法信息:
package com.wws.reflect;
import java.lang.reflect.Method;
public class DumpMethod2 {
public static void main(String[] args) throws Exception
{
//獲得命令行輸入類名的類型
Class<?> classType =Class.forName("arg[0]");
//獲得並返回類的所有方法
Method[] methods =classType.getDeclaredMethods();
for(Method method:methods)
{
System.out.println(method);
}
}
}
傳人蔘數:
效果:
接下來寫個簡單程序
用反射改造:
package com.wws.reflect;
import java.lang.reflect.Method;
import java.sql.ResultSet;
public class InvokeTester {
public int add(int parm1,int parm2)
{
return parm1+parm2;
}
public String echo(String message)
{
return "hello:"+message;
}
public static void main(String[] args)throws Exception
{
/*獲取java類的幾種方法:
通過Class類的靜態方法:forName(XX);
String.class,getClass()*/
Class<?> classType= InvokeTester<strong>.class</strong>;
Object invokeTester =classType.<strong>newInstance()</strong>;
/*System.out.println(invokeTester instanceof InvokeTester);
返回true*/
/*Method java.lang.Class.<strong>getMethod(String name, Class<?>... parameterTypes)</strong>
參數一:目標方法名
參數二:目標方法的參數類型數組*/
Method addMethod=classType.getMethod("add", new Class[]{int.class,int.class} );
/*調用invoke實現對目標方法的調用
* 參數一:實例名
* 參數二:接受什麼參數
* */
Object result=addMethod<strong>.invoke(invokeTester,new java.lang.Object[]{1,2});</strong>
System.out.println((Integer)result);
Method echoMethod=classType.getMethod("echo", new Class[]{String.class});
Object result2=echoMethod.invoke(invokeTester, new Object[]{"wws"});
System.out.println((String)result2);
}
}
運行結果:
通過Class類的靜態方法:
forName(XX);
String.class;
getClass();
newInstance()不會生成帶參數方法的實例,此時應該用Constructor的newInstance(Object ...initargs),即用類getConstructor(new Class[ ] { }).newInstance(new Object[ ]{ });
例子2:實現get,set方法:
public class CopyObject {
public Object copyObject(Object object) throws Exception {
// 1.獲取待操作類的一個Class對象
Class<?> classType = object.getClass();
// 2.獲取待操作類的一個實例
Constructor<?> constructor = classType
.getConstructor(new Class<?>[] {});
Object copyObj = constructor.newInstance(new Object[] {});
// 3.獲取被拷貝類的成員變量
Field[] fields = classType.getDeclaredFields();
for (Field field : fields) {
// 4.遍歷數組獲取各個成員變量名字
String name = field.getName();// 獲取成員變量名字;
// 5.操作字符串獲取成員變量的set和get方法名字;
String firstLetter = name.substring(0, 1).toUpperCase();
String getMethodName = "get" + firstLetter + name.substring(1);
String setMethodName = "set" + firstLetter + name.substring(1);
Method getMethod = classType.getMethod(getMethodName,
new Class<?>[] {});
Method seMethod = classType.getMethod(setMethodName,
new Class<?>[] { field.getType() });
/*最開始認爲以下兩個invoke方法的第一和參數都應該調用copyObj,
* 但是最終的結果爲輸出爲默認的空值。
* copyObj:程序前面通過Constructor類的newInstance方法
* 獲取待操作類的一個實例;
//Object value = getMethod.invoke(copyObj, new Object[] {});
//seMethod.invoke(copyObj, new Object[] { value });
/*現在改用如下方式了,輸出就正常了
* 所以產生疑惑:爲什麼第一個方法調用的object對象而不是copyObj呢?
*
*/
Object value = getMethod.invoke(object, new Object[] {});
seMethod.invoke(copyObj, new Object[] { value });
}
return copyObj;
}
public static void main(String[] args) throws Exception {
Student student = new Student("Tom", 21);
student.setId(111030805);
CopyObject copy = new CopyObject();
Student student2 = (Student) copy.copyObject(student);
System.out.println(student2.getId() + " " + student2.getName() + " "
+ student2.getAge());
}
}
// 一個被反射的JavaBean
class Student {
private long id;
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
更多 0
反射生成數組:
生成多維數組:
輸出結果:37,創建了一個5,10,15的三維數組。
利用反射調用類的私有方法: