前言:
先说说反射的作用。我们都知道处于安全、维护方便等因素的考虑,java中定义了4中访问权限,分别是:private(仅限本类)、默认无关键字(本包内所有类,包含本包内的子类)、protected(本包、其他包的子类)、public(所有类)。然后因为某些特殊的需要,需要访问某些原本不可见的方法(或者字段),比如访问某个Person类内部的某个private方法,则一般的方法是不行的,这个时候反射的作用就体现出来了。
正题:
在Java中的各种操作,无非就是对类、字段、方法这三类操作,因为在反射中,也定义了三个类Class、Field、Method来分别对这三个进行处理(从英文的字面也可以看出来)。
如果我们要获得某个类的字段(或方法),则步骤一般如下:
1、获取该类的“一个Class实例”,比如
Class<Person> mPersonClass=Person.class;
当然,通过Person的实例来获取也可以的,比如有一个mPerson的实例,则这样也可以
Class<Person> mPersonClass=mPerson.getClass();
2、用class实例来获取字段(或方法),比如
Method method=mPersonClass.getDeclaredMethod("setAge",int.class);
这个方法如果成功的话,会得到一个Method实例,如果不成功,则会报错,常见的报错有NoSuchMethodException。
注意:一般对于Method而言,常用的获取方式有getMethod()和getDeclaredMethod()两种,但是更建议用后者,因为前者只当需要反射的方法是public时才有效,如果对于private方法也使用getMethod(),则会报NoSuchMethodException错误!!!getDeclaredMethod()对于private也一样使用。类似的的,对于Field有getField()和getDeclaredField()两种,推荐使用后者,原因是一样的。
getDeclaredMethod()这个方法中有2部分参数,第一部分是方法名,第2部分是声明参数类型,比如在Person类中有private boolean setInfo(String name,int age)方法,则按如下形式,返回值类型不需要加入第2部分的参数中
Method method=mPerson.getDeclaredMethod("setInfo",String.class,int.class)
3、设置可访问,这一点对于private的字段或方法尤其重要,不然一样会报错
method.setAccessible(true);
4、进行方法或字段的操作,对于方法调用,使用method.invoke();需要传入2部分参数:1、调用的对象,2、参数列表(如果方法不需要参数,则不需要;如果需要,则按顺序对应写入,这个和getDeclaredMethod()声明的应该对应)
boolean result=method.invoke(Person.class.newInstance(),20);
//这里讲年龄设置为20,第一部分的参数也可以用你自己获取到的对象
对于field,则有get()和set()方法,原理类似,需传入:对象+参数列表
11/10注:第一个参数是调用对象,如果是反射的是静态方法,则可传入null或者是对象
例子:
现在我有个Person类,通过反射调用其中的方法:
Person.java
package edu.hust.cs;
public class Person {
/**年龄*/
private int age=0;
/**姓名*/
private String name=null;
/**下面的语句块,在创建对象时会调用。
* 顺序为:成员变量>下面的语句块>构造器
* */
{
System.out.println("初始化时,Name:"+name+",Age:"+age);
}
private boolean setPersonInfo(String _name)
{
name=_name;
System.out.println("只设置姓名时,Name:"+name+",Age:"+age);
return true;
}
private boolean setPersonInfo(String _name,int _age)
{
name=_name;
age=_age;
System.out.println("设置姓名和年龄时,Name:"+name+",Age:"+age);
return false;
}
}
测试类Test.java
package edu.hust.cs;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args)
{
try{
//获取一个实例
//当然也可以直接new Person();
Person person=Person.class.newInstance();
//反射"setPersonInfo(String _name)"方法
Method method=person.getClass().
getDeclaredMethod("setPersonInfo",String.class);
//因为原方法为private,所以设置可访问,这一条语句是必须的!
method.setAccessible(true);
//调用该方法,并获取返回结果
boolean result=(boolean) method.invoke(person,"张三");
System.out.println(result);
//反射"setPersonInfo(String _name,int _age)"方法
Method method2=person.getClass().
getDeclaredMethod("setPersonInfo",String.class,int.class);
method2.setAccessible(true);
boolean result2=(boolean) method2.invoke(person,"张三",23);
System.out.println(result2);
}catch(Exception e){
e.printStackTrace();
}
System.exit(0);
}
}
输出结果如下:
初始化时,Name:null,Age:0
只设置姓名时,Name:张三,Age:0
true
设置姓名和年龄时,Name:张三,Age:23
false