JAVA反射總結(2)

上一篇博文,主要回顧了利用反射,可以拿到類中的所有東西,不管是私有的,還是共有的,並且最後一個demo9,利用反射實例化了一個對象,上次最重要的還有怎麼拿到三種反射入口對象Class。這裏就不一一複述了。上篇是知道反射有什麼用。本次主要是對反射的一些應用。

首先我們還是一如既往地準備好測試類,和接口。基本和上個一樣,有一個小改動,後面會說到。

接口分別是myInterface1.java,myInterface2.java,代碼如下:

package com.charles.reflectDemo;
 
public interface myInterface1
{
	public void myInterface1Method();
}
package com.charles.reflectDemo;
 
public interface myInterface2
{
	public void myInterface2Method();
}

再是實現類reflectDemo.java,我們在該測試類中再加入一個方法showMessage(String message),待會用來測試,再說一下,該類屬性有2個私有,1個公有,以及所有get和set方法,三個構造,2個實現接口方法,一個私有無參方法,一個公有有參方法。

package com.charles.reflectDemo;
 
public class reflectDemo implements myInterface1,myInterface2{
	private String name;
	private int id;
	public String desc;
	public reflectDemo(String name, int id, String desc) {
		super();
		this.name = name;
		this.id = id;
		this.desc = desc;
	}
	public reflectDemo(String name, int id) {
		super();
		this.name = name;
		this.id = id;
	}
	public reflectDemo() {
		super();
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getDesc() {
		return desc;
	}
	public void setDesc(String desc) {
		this.desc = desc;
	}
	@Override
	public void myInterface2Method() {
		System.out.println("method myInterface2Method");
	}
	@Override
	public void myInterface1Method() {
		System.out.println("method myInterface1Method");
		
	}
	public void sayHello()
	{
		System.out.println("method sayHello");
	}

    private void showMessage(String message)
    {
        System.out.println("Message is:"+message);
    }
}

準備工作完了,接下來編寫測試類testDemo1.java,其中有如下方法:(爲了方便測試與觀察其主要代碼,我們此處不處理異常)

demo1代碼如下:(通過Class反射入口,然後通過反射實例化對象,並調用對象方法)

 //獲取對象實例,並操作該對象。
	public static void demo1() throws ClassNotFoundException, InstantiationException, IllegalAccessException 
	{
		Class<?> reflectDemoClazz=Class.forName("com.charles.reflectDemo.reflectDemo");
		Object 	reflectDemoObj=reflectDemoClazz.newInstance();
		reflectDemo instance=(reflectDemo)reflectDemoObj;
		instance.setName("charles");
		instance.setId(123456);
		System.out.println(instance.getName()+" "+instance.getId());
	}

執行結果如圖所示:(完成了對象的實例化,並且成功調用方法)通過Class對象的newInstance方法來得到一個Object對象,經過強轉成爲reflectDemo對象;用該對象調用該類成員方法即可!

 

demo2代碼如下:(通過Class反射入口,調用getDeclaredField(String FieldName)方法,返回一個Field屬性對象代表反射類中的一個屬性,該方法的參數是一個屬性名,比如reflectDemo 類中的name屬性,通過參數就可以拿自己想要的屬性。後面,同樣和demo1類似,我們也產生一個reflectDemo 類對象待用。Field類對象調用set方法,即可爲該數據成員賦值,set(Object obj,Object obj),該方法的參數都是object類型,第一個代表的是該類的一個對象,第二個代表給屬性的賦值,相當於我們平常的想要爲一個屬性賦值就用: 對象.setXXX(參數類型 形參名)。此處是反射,我們拿到的是一個屬性,其實就相當於順序變了一下,此處是: 屬性.set(對象,屬性值)),先不多說,我們來觀察執行結果!

	public static void demo2() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException
	{
		Class<?> reflectDemoClazz=Class.forName("com.charles.reflectDemo.reflectDemo");
		Object 	reflectDemoObj=reflectDemoClazz.newInstance();
		reflectDemo instance=(reflectDemo)reflectDemoObj;
		Field fieldName=reflectDemoClazz.getDeclaredField("name");
        //空白處
		//fieldName.setAccessible(true);
		fieldName.set(instance, "charles");
		System.out.println(instance.getName());
	}

執行結果:異常!

Exception in thread "main" java.lang.IllegalAccessException: Class com.charles.reflectDemo.testDemo1 can not access a member of class com.charles.reflectDemo.reflectDemo with modifiers "private"
    at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(Unknown Source)
    at java.lang.reflect.AccessibleObject.checkAccess(Unknown Source)
    at java.lang.reflect.Field.set(Unknown Source)
    at com.charles.reflectDemo.testDemo1.demo2(testDemo1.java:26)
    at com.charles.reflectDemo.testDemo1.main(testDemo1.java:63)

解釋:我們拿的屬性是reflectDemo中的私有屬性 private String name,Java私有屬性不能被外界訪問,所以此處報異常。解決方法:

我們拿到了屬性Field fieldName對象,代表一個屬性,我們可以用該對象調用一個方法:setAccessible(true);即可將該私有屬性設置爲可以訪問,現在我們將以下代碼插入到上段代碼註釋的空白處

	fieldName.setAccessible(true);

,執行觀察;如下;

我們通過反射,爲該類對象的私有成員成功賦值,並且成功訪問!

demo3代碼如下:(demo2和demo3相似,都是拿屬性,但是demo2拿的是私有屬性,demo3拿的是公共屬性,所以不用setAccessible(true)來設置其可以訪問

//獲取reflectDemo類的public desc屬性並賦值測試
	public static void demo3() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException
	{
		Class<?> reflectDemoClazz=Class.forName("com.charles.reflectDemo.reflectDemo");
		Object 	reflectDemoObj=reflectDemoClazz.newInstance();
		reflectDemo instance=(reflectDemo)reflectDemoObj;
		Field fieldName=reflectDemoClazz.getDeclaredField("desc");
		fieldName.set(instance, "this is public field");
		System.out.println(instance.getDesc());
	}

執行結果:沒毛病

demo4代碼如下:(和之前一樣我麼先拿Class反射入口,然後通過入口實例化一個對象,demo4主要是拿公有方法並執行,我們之前定義了一個sayHello方法,所以我們用此方法爲例。我們先執行,再分析!)

	//獲取reflectDemo類的public myInterface1Method方法並測試
	public static void demo4() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
	{
		Class<?> reflectDemoClazz=Class.forName("com.charles.reflectDemo.reflectDemo");
		Object 	reflectDemoObj=reflectDemoClazz.newInstance();
		reflectDemo instance=(reflectDemo)reflectDemoObj;
		Method method=reflectDemoClazz.getDeclaredMethod("sayHello", null);
		method.invoke(instance,null);
	}

 

執行結果:執行成功,並且打印了該方法的輸出語句;

分析:我們通過反射入口對象,調用該對象方法getDeclaredMethod("sayHello", null);返回一個Method類型對象,代表一個你想要拿到方法,注意,該方法有多個重載,第一個參數是你要反射拿的方法名,後面的參數是你想反射的方法的參數,因爲我的這個例子中沒有參數,所以爲null,然後,我們通過Method類對象,就可以執行該方法,用invoke(instance,null);第一個參數是該類的對象,後面的參數是參數值因爲該方法無參,所以爲null,再來思考它是如何執行的;

我們拿到的是一個代表方法的對象,然後用該對象的invoke方法將對象和參數傳進去就可以執行:

method.invoke(obj,para1,para2...),

思考我們平常的執行順序,是對象.方法(參數1,參數2....)即:

obj.method(para1,para2....),,

不難理解,其實就是順序的一些變化。

demo5代碼如下:(demo4是拿的一個公有的方法,並且無參,demo5拿的是私有方法帶參,循序漸進,先看代碼執行結果再來分析!)

//獲取reflectDemo類的private showMessage方法並測試
	public static void demo5() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
	{
		Class<?> reflectDemoClazz=Class.forName("com.charles.reflectDemo.reflectDemo");
		Object 	reflectDemoObj=reflectDemoClazz.newInstance();
		reflectDemo instance=(reflectDemo)reflectDemoObj;
		Method method=reflectDemoClazz.getDeclaredMethod("showMessage", String.class);
		method.setAccessible(true);
		method.invoke(instance, "hello reflect method");
	}

執行結果:成功輸出信息並打印!

理解:和demo4一樣,先拿反射入口對象,通過該對象的方法拿到代表方法的對象,和該反射類實例對象,此處我們測試帶一個String類型參數,所以我們的方法是.getDeclaredMethod("showMessage", String.class);和demo4一樣,該方法第一個參數是傳入一個想要通過反射獲得的方法名,後面的參數是該方法列表的參數類型,而且也是Class類型。因爲我們此處訪問的是私有方法,所以直接訪問依舊會報異常,回顧我們demo2,此處我們依舊需要設置一下,讓該方法讓外外界可以訪問,一樣也用setAccessible(true);方法即可,最後,用代表該方法的對象執行method.invoke(instance, "hello reflect method");就完成了方法的反射執行,第一個參數和demo4一樣,是該反射類的實例對象,後面的參數是具體傳入的值。

demo執行分析完畢!

下次有空寫JAVA反射總結(3) 

over!

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