Java--反射机制与使用
Java的反射机制可以说是让其能够具有容易移植的方便,也是Java语言的特点之一。
在反序列化调用链子中经常能看到反射的使用,今天就来学习一下:
反射的使用
这里写一个demo,正常调用这个Study类
package reflect; public class Study { private int num; public int getNum(){ return num; } public void setNum(int num){ this.num = num; } public static void main(String[] args) throws Exception{ Study study = new Study(); study.setNum(21); System.out.println("Your age is ~"+study.getNum()); } }
运行结果当然就是,这我们可以理解成Java的"正"射调用
那么调用反射就需要使用到一些API,下面这两个类肯定是需要引用的
import java.lang.reflect.Constructor;
import java.lang.reflect.Method
我学着写了一个ReUse类来对Study类进行反射调用
package reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class ReUse { public static void main(String[] args) throws Exception { //获取需要反射调用的类 对象实例 Class my = Class.forName("reflect.Study"); //通过my获取构造函数对象 studyConstructor Constructor studyConstructor = my.getConstructor(); //studyConstructor来使用newInstance()方法来获取反射的对象 Object studyObj = studyConstructor.newInstance(); //下面这样写与上面等价 // Study studyObj = (Study)studyConstructor.newInstance(); //通过Study对象实例my获取反射调用的方法对象 Method setNumMethod = my.getMethod("setNum", int.class); Method getNumMethod = my.getMethod("getNum"); //执行 setNumMethod.invoke(studyObj,21); int str = (int) getNumMethod.invoke(studyObj); System.out.println("Your age is ^"+str); } }
简单来说使用过程就是:获取反射类的对象my-->通过该对象获取构造函数对象Constructor
-->然后在通过构造函数对象使用newInstance()方法来获取反射对象(这里也可以直接用my对象来获取,下面会说两种区别)
Method 对象就是通过my来获取对应的方法的,该对象调用invoke()方法传入反射对象和参数等就可以调用反射对象的内置方法了
获取反射中的Class对象
有三种方法可以获取:
1.class.forName()
上面demo所用的就是第一种方法,当知道反射类的全路径时可以用这种方法。
2.使用.class()方法
在编译前就知道该Class,什么意思 比如我这个ReUse和Study处在一个package下就可以直接使用,
是等价的
//Class my = Class.forName("reflect.Study"); Class my = Study.class;
3.使用类对象的getClass()方法
在我们有该Class的对象时候,可以调用该对象的getClass()方法来直接获取
Study study = new Study(); Class my = study.getClass();
通过反射类创建对象
也就是前面说到的可以用my或者是用构造函数Constructor对象来获取反射对象
第一种:
Object studyObj = my.newInstance();
第二种:
//通过my获取构造函数对象 studyConstructor Constructor studyConstructor = my.getConstructor(); //studyConstructor来使用newInstance()方法来获取反射的对象 Object studyObj = studyConstructor.newInstance();
两者的区别就是通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法.
通过反射获取类的属性、方法和构造器
通过Class对象的getDeclaredFields()可以获取包括私有属性的所有属性
//获取反射类 属性 方法 Field[] names = my.getDeclaredFields(); for (Field field: names){ System.out.println(field.getName()); }
这里输出private的num
还有一种方法是getFields(),但是无法获取私有属性。
Field是一个类,位于java.lang.reflect包下。在Java反射中Field类描述的是类的属性信息。
可参考:Field用法
在用Method 创建对象获取反射方法时
受保护成员和私有成员,在分别使用Field、Method和Constructor对象来设置或获得字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。
当反射对象的accessible标志设为true时,则表示反射的对象在使用时应该取消Java语言访问检查。反之则检查。
由于JDK的安全检查耗时较多,所以通过setAccessible(true)的方式关闭安全检查来提升反射速度。
比如这里我把getNum()方法改成private
直接反射调用就会报错了
怎么办呢?把getMethod()改成用getDeclaredMethod()加上Declared,并设置setAccessi为true这样就能访问到
Private的方法了