上一篇博文,主要回顧了利用反射,可以操作類中的所有方法和屬性,本次,我們來使用反射來操作比較特殊的方法:構造方法。第一篇博文已經講過如何拿構造方法,這裏就不多說。本次主要回顧使用構造方法來實例化該反射類對象。
首先依舊是準備好測試類,本次反射測試類是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);,將該代碼加在上面代碼中標記的空白處,然後執行。觀察:正常!