反射的具体原理以后说明,以下面代码实例来说明反射的应用。
先写一个Person类
package exercise01; public class Person { private String name; private int age; //无参构造方法 public Person() { } //有参构造方法 public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
获取Class对象的三种方法
Class clazz1 = Person.class; Class clazz2 = new Person()。getClass(); Class clazz3 = Class.forName("exercise01.Person"); //forName方法的参数是类的路径,即包名加类名
Class对象中有三个数组,分别是
private Constructor[] constructor; //构造方法数组,存放目标类的构造器 private Field[] field; //属性数组,存放目标类属性 private Method[] method; //普通方法数组,存放目标类的普通方法
得到三个数组的方法
@Test public void getAll() throws Exception { Class clazz = Person.class; //得到构造器的数组 Constructor[] constructor = clazz.getConstructors(); //得到属性的数组 Field[] field = clazz.getDeclaredFields(); //得到普通方法的数组 Method[] method = clazz.getDeclaredMethods(); }
注意:
如果Class对象想设置目标类的私有属性或方法,要添加下面这个语句
//获取Class对象 Class clazz = Person.class; //获取Person类中的name属性 Field field = clazz.getDeclaredField("name"); //name的访问权限是private,通过下面语句获取权限,r然后Field对象就可以为name属性赋值了 field.setAccessible(true);
调用目标类的无参构造方法
//获取无参的构造方法 @Test public void getConstructor() throws Exception { //获取Class类对象 Class clazz = Person.class; //得到Person的实例 Person p = (Person)cla.newInstance(); p.setName("example"); System.out.println(p.getName()); }
调用目标类的有参构造方法
@Test public void getConstructors() throws Exception{ Class clazz = Person.class; //传递的是有参构造方法里的参数类型,类型是class的形式 /* * 这里int的class形式要用int.class,而不是Integer.class * 如果要用Integer.class,要把Person类的age改成Integer类型 */ Constructor cs = clazz.getConstructor(String.class, int.class); //通过有参数的构造方法设置值 Person p1 = (Person)cs.newInstance("lila", 24); System.out.println(p1); }
使用目标类的属性
@Test public void getField() { try { Class clazz = Class.forName("exercise01.Person"); //得到name属性 //c2.getDeclaredFields(); //得到所有的属性 Field field = clazz.getDeclaredField("name");
//使用Person的无参构造方法实例化一个Person对象 Person person = (Person)clazz.newInstance(); //设置访问权限,使field可以操作私有属性 field.setAccessible(true); //设置person对象的name属性 field.set(person, "example"); System.out.println(f1.get(person)); }catch(Exception e) { e.printStackTrace(); } }
使用目标类的普通方法
@Test public void getMethod() throws Exception{ Class clazz = Class.forName("exercise01.Person"); //使用Person类的无参构造方法实例化一个Person对象 Person person = (Person)clazz.newInstance(); //获取一个Method对象,该方法包含Person类的setName方法 /* * getDeclaredMethod方法第一个参数是目标类的目标方法名,第二个参数是目标方法的参数类型的class形式 * 可以把目标方法的所有参数都写进去 */ Method method = clazz.getDeclaredMethod("setName", String.class); //设置权限 method.setAccessible(true); method.invoke(person, "example"); //访问静态方法 //method.invoke(null, "example"); System.out.println(person.getName()); }
这里有个值得注意的地方,如果要调用目标类的静态方法,此时invoke方法的书写方法有点不同。
因为调用静态方法,不必实例化一个对象,可以通过类名直接调用,所以当使用静态方法时,invoke方法的第一个参数写成null,第二个参数写静态方法的参数的值,比如
method.invoke(null, "example");