一、 何为反射机制
简单来说,反射机制指的是程序在运行过程中能够获取自身的信息。反射机制在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个属性和方法(包括私有的,是不是好可怕,没有隐私了。。);这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。
二、 反射机制主要的功能
在运行时判断一个对象所属的类;
在运行时获取任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理;
在继续往下面深入之前,咱们先来简单说一下要想使用一个类需要完成的三个步骤:
加载(根据字节码创建一个Class对象);
链接(验证类中的字节码,为静态域分配存储空间);
初始化(如果该类有超类,则先对超类进行初始化,执行静态初始化器和静态初始块)
对于每一个类,在内存中只有唯一的一个Class对象,也就是每一个类的class文件信息在内存中对应唯一的一个Class对象的引用。因此,我们只要能够获得对应类的Class引用。则关于类的所有信息都能知道不是吗?因为类的所有信息都是可以通过class文件获得的。
获取一个类的Class对象的三种方式:(假设有一个Person类,它的一个实例对象为person,这个类所在的包为:com.jcw.test)
- 通过实例对象获得:Class c1 = person.getClass();
- 通过Class类的静态方法-forName()获得:Class c2 = Class.forName(“com.jcw.test.Person”);
- 通过一个类的默认属性获得-class:Class c3 = Person.class
三、 利用反射机制获得的信息
一句话,类中有什么信息,它就可以获得什么信息,不过需要首先知道类的名字,并且能够通过相应的类加载器找到对应的类。
获取构造函数的方法
Constructor getConstructor(Class… parameterTypes) //根据指定的参数获取对应的public构造器
Constructor[] getConstructors()//获取所有的public构造器
Constructor getDeclaredConstructor(Class… parameterTypes)//根据指定参数获取public或非public构造器
Constructor[] getDeclaredConstructors()//获取所有的构造器
获得类方法的方法
Method getMethod(String name, Class… parameterTypes)//根据方法名和给定的参数获得public方法
Method[] getMethods()//获取所有的public方法
Method getDeclaredMethod(String name, Class… parameterTypes)//根据方法名和指定的参数获得方法
Method[] getDeclaredMethods() //获得所有的方法
获得类中属性的方法
Field getField(String name)//根据变量名得到相应的public变量
Field[] getFields()//获得所有的public方法
Field getDeclaredField(String name)//根据方法名获得变量
Field[] getDeclaredFields()//获得所有的变量
四、用反射机制来做一些事情
首先定义一个Person类:
package com.jcw.reflect;
public class Person {
public String name = "defaultName";
private String age = "defaultAge";
//无参构造器
public Person(){}
//有参构造器
public Person(String name, String age) {
this.name = name;
this.age = age;
}
public void say() {
System.out.println("我上课在说话,你敢吗?");
}
private void run() {
System.out.println("放学了,我跑了出去");
}
}
在Person类中,有一个public变量name,一个private变量age,一个public方法say,一个private方法run。正常情况下,变量age和方法run()在外部是访问不到的,也是不能够修改的。下面通过测试看咱们怎样访问到这些按理是访问不到的private成员和方法。
定义一个测试类:
package com.jcw.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class PersonTest {
public static void main(String[] args) throws Exception {
/**
*最原始的实例化一个person对象
*/
Person person = new Person();
person.say();
//我想调用Person类中的私有方法run(),但是访问不了
//person.run();
System.out.println("person.name: " + person.name);
//我想访问Person类的中私有成员变量age,但是访问不了
//System.out.println(person.age);
/**
* 通过反射机制来获得构造器的方式来获取一个Person的实例
*/
Class<Person> class1 = Person.class;
Constructor<Person> constructor = class1.getConstructor();
constructor.setAccessible(false);
Person person1 = constructor.newInstance();
//我想访问私有run()方法,看下面反射机制如何访问。
Method method1 = class1.getDeclaredMethod("run");
//这一句话保证了私有方法也能够被调用
method1.setAccessible(true);
//这一步将会成功地调用run方法
method1.invoke(person1);
System.out.println("person1.name: " + person1.name);
//我想访问私有的成员变量age
Field field1 = class1.getDeclaredField("age");
//这一句话保证了这个私有成员变量也能够被访问
field1.setAccessible(true);
System.out.println("person1.age: " + field1.get(person1));
//修改age变量的值
field1.set(person1,"我是修改过的值");
System.out.println("person1.age: " + field1.get(person1));
}
}
Output:
根据分析,我们成功访问到了private的成员和方法,并且还成功修改了age的值。其中一句话比较重要,就是调用setAccessible(true)。
总结:上述就是简单的说明了一下反射机制的作用,可以看到通过反射,我们能够访问到正常访问不到的东西,而且上面的代码可以整理为一个模板,只能传入对应的类名,方法名,成员变量名,就能够访问想访问的东西。其中反射机制在一些框架(比如SSH,mybatis等)使用的比较多,像动态代理,AOP等都用到了反射机制。大家可以了解下这个东西,以后在学框架,动态代理等知识时,能够极大减轻学习的负担。
有说不对的地方,请各位指正。。