JAVA反射總結(3)

上一篇博文,主要回顧了利用反射,可以操作類中的所有方法和屬性,本次,我們來使用反射來操作比較特殊的方法:構造方法。第一篇博文已經講過如何拿構造方法,這裏就不多說。本次主要回顧使用構造方法來實例化該反射類對象。

首先依舊是準備好測試類,本次反射測試類是Person.java,該類三個屬性以及相應的get和set方法,以及公有和私有的帶參與不帶參的構造方法。代碼如下:

package com.charles.reflectDemo;

public class Person {
	private String name;
	private String desc;
	private int id;
	public Person(String name, String desc, int id)
	{
		this.name = name;
		this.desc = desc;
		this.id = id;
	}
	public Person(String name, String desc) 
	{
		this.name = name;
		this.desc = desc;
	}
	public Person(int id)
	{
		this.id = id;
	}
	public Person()
	{
	}
	private Person (String name)
	{
		this.name=name;
	}
	
	public String person()
	{
		return name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public String getDesc()
	{
		return desc;
	}
	public void setDesc(String desc)
	{
		this.desc = desc;
	}
	public int getId()
	{
		return id;
	}
	public void setId(int id)
	{
		this.id = id;
	}
	public String getName() {
		return name;
	}

}

測試類是testDemo3.java,其主要作用如下圖:

 

demo1代碼如下:

 //先拿person中的所有構造,並顯示
	public static void demo1() throws ClassNotFoundException 
	{
		Class<?> PersonClazz=Class.forName("com.charles.reflectDemo.Person");
		Constructor[] constructors=PersonClazz.getDeclaredConstructors();
		for(Constructor constructor: constructors)
		{
			System.out.println(constructor);
		}
	}

執行結果如下圖:(這裏就不解釋了,博文1裏面已經提到,這裏我們只是用來展示該類的所有構造方法,觀察得知,一共有3個公有帶參,一個公有無參,1個私有帶參,,後面我們用它們來做示例)

 

demo2代碼如下:我們拿一個代表該反射類的公有無參構造方法的對象,通過這個對象來實例化該反射類對象並顯示。

//拿公有無參構造,實例化反射類的對象
	public static void demo2() throws ClassNotFoundException
, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
	{
		Class<?> PersonClazz=Class.forName("com.charles.reflectDemo.Person");
		Constructor constructor=PersonClazz.getDeclaredConstructor();
		Person person=(Person)constructor.newInstance();
		person.setName("charles");
		person.setId(123456);
		System.out.println(person.getName()+" "+person.getId());
	}

執行結果如圖所示:

 分析:我們通過反射入口Class對象,拿到了代表反射類的一個無參構造的對象:constructor。

Constructor constructor=PersonClazz.getDeclaredConstructor();

之前我們可以通過反射直接實例化該反射類對象,方法是:例如:

Object  reflectDemoObj=reflectDemoClazz.newInstance();

衆所周知,在java中我們可以通過new來實例化對象,其本質其實是使用構造函數,比如:Person person=new Person();

所以,通過反射,我們一樣可以用構造方法來實例化對象,此例代碼如下:

Person person=(Person)constructor.newInstance();

我們通過代表該反射類的構造方法的對象的newInstance();方法來實例化一個對象,返回值爲Object類型,我們將其強轉爲Person類型,再用該Person對象調用該類的set和get方法完成該demo

 

demo3代碼如下:我們拿一個代表該反射類的公有帶參構造方法的對象,通過這個對象來實例化該反射類對象並顯示。

	//拿公有帶參構造,實例化反射類的對象
	public static void demo3() throws ClassNotFoundException
, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
	{
		Class<?> PersonClazz=Class.forName("com.charles.reflectDemo.Person");
		Constructor constructor=PersonClazz.getDeclaredConstructor(int.class);
		Person person=(Person)constructor.newInstance(123456);
		person.setName("charles");
		System.out.println(person.getName()+" "+person.getId());
	}
	

執行結果如圖所示:

分析:與demo2類似,都是拿構造方法並實例化對象。但此處的構造方法帶參,因此,我們怎麼去拿或者是確定帶參的構造方法呢?代碼如下:    Constructor constructor=PersonClazz.getDeclaredConstructor(int.class);與demo2看起來相似,只是在getDeclaredConstructor(int.class)中多了一個參數,int.class。解釋一下,getDeclaredConstructor()這個方法有很多重載,其中參數個數不同但都是Class類型,用來匹配構造函數的參數類型,因爲此處我們的Person類有一個只帶一個int 型參數的構造方法,所以這裏我們只需要寫一個int.class  。

注意:不能寫成integer.class,這樣會報如下異常

Exception in thread "main" java.lang.NoSuchMethodException: com.charles.reflectDemo.Person.<init>(java.lang.Integer)
    at java.lang.Class.getConstructor0(Unknown Source)
    at java.lang.Class.getDeclaredConstructor(Unknown Source)
    at com.charles.reflectDemo.testDemo3.demo3(testDemo3.java:35)
    at com.charles.reflectDemo.testDemo3.main(testDemo3.java:56)

原因:在反射中,基本類型和包裝類型是兩種不同的類型,例如int和Integer,char和Character,所以需要特別注意一下。

接下來就是利用這個代表構造方法的對象來實例化Person類對象,調用newInstance();方法,該方法也被重載了,此處我們需要填入一個參數,就是你調用構造方法時具體需要傳入的值。再用該Person對象調用該類的set和get方法完成該demo;

demo4代碼如下:demo2和3都是拿公有構造,此處我們來嘗試拿私有帶參構造。

//拿私有帶參構造,實例化反射類的對象
	public static void demo4() throws ClassNotFoundException
, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
	{
		Class<?> PersonClazz=Class.forName("com.charles.reflectDemo.Person");
		Constructor constructor=PersonClazz.getDeclaredConstructor(String.class);
        //空白處
		Person person=(Person)constructor.newInstance("charles");
		person.setId(123456);
		System.out.println(person.getName()+" "+person.getId());
	}

執行結果如下所示:異常!

Exception in thread "main" java.lang.IllegalAccessException: Class com.charles.reflectDemo.testDemo3 can not access a member of class com.charles.reflectDemo.Person 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.Constructor.newInstance(Unknown Source)
    at com.charles.reflectDemo.testDemo3.demo4(testDemo3.java:47)
    at com.charles.reflectDemo.testDemo3.main(testDemo3.java:57)

分析:觀察我們的代碼,會發現,似乎基本和demo3一樣,但是demo3拿的是公有的構造,我們此處拿的是私有的構造,那麼到底哪裏不一樣呢回想一下之前的博文2,要使用私有屬性或者方法,我們必須通過反射來設置讓其可以訪問。需要設置
constructor.setAccessible(true);,將該代碼加在上面代碼中標記的空白處,然後執行。觀察:正常!

通過上述demo的使用,本次基本可以用反射的構造方法來完成對象的實例化,但是在實際開發或者運用中,一般不要用反射來操作私有屬性,方法等,因爲這樣違背了java的一些特性,會造成代碼混亂。好了,demo書寫示例完畢!

下一次有空寫JAVA反射總結4,利用反射來越過泛型約束,通過配置文件的方式使用泛型,編寫泛型工具類等!

over!

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