上一篇博文,主要回顾了利用反射,可以操作类中的所有方法和属性,本次,我们来使用反射来操作比较特殊的方法:构造方法。第一篇博文已经讲过如何拿构造方法,这里就不多说。本次主要回顾使用构造方法来实例化该反射类对象。
首先依旧是准备好测试类,本次反射测试类是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);,将该代码加在上面代码中标记的空白处,然后执行。观察:正常!