上一篇博文,主要回顾了利用反射,可以拿到类中的所有东西,不管是私有的,还是共有的,并且最后一个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执行分析完毕!