java反射機制講解及示例

java反射機制作用:
在運行時判斷任意一個對象所屬的類
在運行時構造任意一個類的對象
在運行時判斷任意一個類所具有的成員變量和方法
在運行時調用任意一個對象的方法

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的三維數組。

利用反射調用類的私有方法:





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