一、反射机制的概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
一般情况,java程序在运行的时候,会先通过Bootstrap ClassLoader 最顶层的加载类,主要加载核心类库,%JRE_HOME%\lib下的jar包;
Extention ClassLoader 扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件;Appclass Loader也称为SystemAppClass 加载当前应用的classpath的所有类,即自己写的经过编译过后的字节码文件。在程序运行过程中,实例化对象是,就将对应的加载了的类对象存方到堆内存之中,以供使用,如下图:
Extention ClassLoader 扩展的类加载器,加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件;Appclass Loader也称为SystemAppClass 加载当前应用的classpath的所有类,即自己写的经过编译过后的字节码文件。在程序运行过程中,实例化对象是,就将对应的加载了的类对象存方到堆内存之中,以供使用,如下图:
如果需要使用编译时没有被编译的类(也就是运行时没有被jvm加载到内存之中的类),获取类中的各种信息,java反射机制能够实现这种功能。
二、使用反射机制的步骤
(1)获取类的class文件;
(2)通过class文件获取类中的方法、变量等信息;
(3)使用反射API来操作这些信息。
其中获取class文件有三种方式。第一种是对象名.getClass(),需要有此类的实例化对象才能用,但是如果已经有对象了,可以直接调用类中的方法和属性了,再通过反射来获取的话就多此一举了;第二种是类名.class,需要导入类所在的包,用起来较为繁琐;第三种是通过Class类的静态方法forName()获取,常用这种方法,因为只需要输入类名的字符串即可。
三、代码示例
public class TestReflect { private Class c; { try { c = Class.forName("com.enroll.POJO.EntryForm"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } @Test public void constructorTest() throws Exception { //get c.class Class c = Class.forName("com.enroll.POJO.EntryForm"); //get a constructor with no parameterType Constructor constructor = c.getConstructor(); System.out.println(constructor + "\n"); Constructor[] constructors = c.getConstructors(); //get all constructors for (Constructor constructor1 : constructors) System.out.println(constructor1); System.out.println(); //get a constructor with String/Integer parameterType Constructor constructor1 = c.getConstructor(String.class, int.class); System.out.println(constructor1 + "\n"); } @Test public void methodTest() throws Exception { //all methods Method[] methods = c.getDeclaredMethods(); //too many to show System.out.println(methods.length); //get setName() Method method = c.getMethod("setName", String.class); System.out.println(method); } @Test public void fieldTest() throws Exception { //get all fields include private field Field[] fields = c.getDeclaredFields(); System.out.println(fields.length); //public field Field[] fields1 = c.getFields(); for (Field field : fields1) System.out.println(field); //get String test1 throws Exception Field field = c.getField("test"); System.out.println(field); } @Test public void reflectTest() throws Exception { //new object throws Exception Object o = c.newInstance(); Method method = c.getMethod("reflect", String.class); // method.setAccessible(true); System.out.println(method.invoke(o, "123456")); } }
四、暴力反射
如何获取和使用类中的私有属性和方法呢?答案是通过“暴力反射”。反射里的Constructor,Field,Method三个类都有一个getDeclaredXxx方法,可以不受权限控制的获取类的构造函数,字段,方法,如果想要私有构造函数创建对象,字段赋值,方法调用的话,会自动的访问类的isAccessable,默认的是false,所以,你要想访问类中的私有成员的时候,就要调用setAccessable方法,将其改为true,这样就可以对类中的私有成员进行操作了。