大家都知道,Java是面向对象的语言,在Java中我们可以通过类的对象访问变量,执行方法,对于方法,变量,类而言,其有固定修饰符(public protected private)表明其作用范围,那么我们如果要无视修饰符直接访问类的方法和变量应该怎么做呢?比如直接构造框架的private修饰的类的实例对象,访问某一对象的private成员等,此时就需要用到反射了。
反射是在运行状态下,直接操作类或对象内部属性的一种方法,其是破坏类封装性的一种表现,反射机制主要提供以下能力:
- 运行时判断任意对象所属类的能力
- 运行时构造任意类实例对象的能力
- 运行时判断一个类所具有的成员变量和方法的能力
- 运行时获取任意对象的任意成员和执行任意方法的能力
通过反射构造类并调用方法的流程如下:
-
获取类的Class对象
// ClassName为String类型,是包含包名的全路径名称,比如com.example.hello下的A类,则 // className = com.example.hello.A Class personClass = Class.forName(ClassName); -
调用Class对象的newInstance方法
// 调用class对象创建类的实例对象 Object person = personClass.newInstance(); -
获取对象的Method
// getMethod方法的第一个参数为方法名,随后的参数为参数类型,该函数为不定参函数 // 参数类型顺序与函数声明顺序一致 Method method = personClass.getMethod("setName", String.class); -
执行Method
// 针对构建的对象执行函数,第一个参数为对象,第二个参数为参数对应的取值 // 取值传入顺序与函数声明的参数顺序一致,该函数为不定参函数 method.invoke(person,"Hello");
接下来我们来看下反射调用Person类的示例代码,Person类声明如下图所示:
反射构造Person类对象,并调用setName,getName的实例代码及运行结果如下所示:
获取类的Class对象
一般情况下,我们有三种方式获取类的Class对象:
-
通过Class.forName方法,适用于知道类的全路径的情况
-
通过类的.class方法,适用于知道类名的情况
Class clz = Person.class; -
通过类对象,适用于只有对象的情况
Person personx = new Person("XXXX"); Class cla = personx.getClass();
构造类的对象
一般情况下,我们有三种方式构造类的对象:
-
通过Class对象的newInstance方法
Object person = personClass.newInstance(); -
通过Constructor对象的newInstance方法
// getConstructor传入的为构造函数需要的参数,该函数为不定参函数 Constructor constructor = clz.getConstructor(String.class); // newInstance传入的是参数具体的取值,该函数为不定参函数 Object person1= constructor.newInstance("Hello");通过Constructor构造时,可以按需选择类的构造器相对而言更加灵活
反射获取类构造方法,属性和其他方法
-
获取类的公共成员:Class.getFields
Class clz = Class.forName("com.example.code.Person"); Field[] fileds = clz.getFields(); for (Field field:fileds) { System.out.println(field.getName()); } -
获取类的所有成员:Class.getDeclaredFields()[不包含父类成员]
Class clz = Class.forName("com.example.code.Person"); Field[] fileds = clz.getDeclaredFields(); for (Field field:fileds) { System.out.println(field.getName()); } -
获取类的所有公共方法:Class.getMethods()[包含父类公共方法]
Class clz = Class.forName("com.example.code.Person"); Method[] fileds = clz.getMethods(); for (Method field:fileds) { System.out.println(field.getName()); } -
获取类的所有方法:Class.getDeclaredMethods()[不包含父类方法]
Class clz = Class.forName("com.example.code.Person"); Method[] fileds = clz.getDeclaredMethods(); for (Method field:fileds) { System.out.println(field.getName()); } -
获取类的公共构造:Class.getConstructors
Class clz = Class.forName("com.example.code.Person"); Constructor[] fileds = clz.getConstructors(); for (Constructor field:fileds) { System.out.println(field.getName()); } -
获取类的所有构造函数:Class.getDeclaredConstructors()
Class clz = Class.forName("com.example.code.Person"); Constructor[] fileds = clz.getDeclaredConstructors(); for (Constructor field:fileds) { System.out.println(field.getName()); } -
利用反射创建数组
-
使用反射获取类注解:Class.getAnnotations和Class.getDeclaredAnnotations