Java 的反射机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。
这种动态获取程序信息以及动态调用对象的功能称为 Java 语言的反射机制。反射被视为动态语言的关键。
反射的作用
- 在运行时判断任意一个对象所属的类。
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类所具有的成员变量和方法。
- 在运行时调用任意一个对象的方法。
- 生成动态代理。
反射就像一面镜子,它可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。
通过反射操作类
要想剖解一个类,必须先要获取到该类的字节码文件对象。而剖解使用的就是 Class 类中的方法。所以先要获取到每一个字节码文件对应的 Class 类型的对象。
// 获取到Person的类类型对象
// 1. 通过类获取类类型对象
Class c1 = Person.class;
// 2. 通过字符串(完整类路径)获取到类类型对象
Class c2 = Class.forName("com.dailyblue.java.reflection.Person");
// 3. 通过对象获取到当前对象的类类型对象
Person p = new Person();
Class c3 = p.getClass();
// 4. 只有8大原始类型的封装类有这个方法
Class c4 = Integer.TYPE;
三种获取类对象方式
Class 类的常见方法
通过反射操作对象
通过刚才的方式,我们获取到了类的类型对象(字节码文件对象),下来我们需要进一步通过这个类的类型对象获取到该类的实例对象。
// 1. 获取类Class c = Class.forName("com.dailyblue.java.reflection.Person");// 2.1 获取Person类的对象Person p1 = new Person();Person p2 = new Person(1);// 2.2 通过反射获取Person类的对象// 获取到Person类的所有构造器Constructor[] constructors = c.getDeclaredConstructors();for (Constructor c1 : constructors) {System.out.println(c1);}System.out.println("----------------------------------------------------------");// 获取到具体某个构造器Class[] 形式参数列表 = {};Constructor con1 = c.getDeclaredConstructor(形式参数列表);Constructor con2 = c.getDeclaredConstructor(Integer.class);Constructor con3 = c.getDeclaredConstructor(Integer.class, String.class);System.out.println(con1);System.out.println(con2);System.out.println(con3);System.out.println("----------------------------------------------------------");// 通过构造器获取类的对象Object obj1 = con1.newInstance();Object obj2 = con2.newInstance(3);Object obj3 = con3.newInstance(4, "admin");System.out.println(obj1);System.out.println(obj2);System.out.println(obj3);
通过反射操作属性
我们已经获取到类的字节码对象,也通过字节码对象获取到该类的实例对象。下来我们来看看如何操纵类中的属性。
Field 类概述
Field 类代表某个类中的一个成员变量。 Field 完整类名为 java.lang.reflect.Field,它提供类或接口中单独字段的信息,以及对单独字段的动态访问。
Field 类的常见方法
相关代码
Class c = Class.forName("com.dailyblue.java.reflection.Student");Object obj = c.getDeclaredConstructor().newInstance();// 获取所有属性// 获取所有定义的属性Field[] fields1 = c.getDeclaredFields();// 获取所有拥有的public属性(包含继承下来的)Field[] fields2 = c.getFields();// 在所定义的属性中查找指定名称的属性Field f1 = c.getDeclaredField("no");Field f2 = c.getDeclaredField("schoolName");// 在所拥有的public属性中查找指定名称的属性Field f3 = c.getField("name");System.out.println("---------------------------------------");// 给属性赋值f1.setAccessible(true); // 设置私有属性可以访问f1.set(obj,1);f2.set(obj,"西北大学");System.out.println("---------------------------------------");// 获取属性的值Object v1 = f1.get(obj);Object v2 = f2.get(obj);
通过反射操作方法
Method 类的概述
Method 的方法提供了对于在类或接口中单个方法的信息和访问,反射方法可能是一个类方法或实体方法(包含抽象方法)。
Method 类的常见方法
相关代码
// 获取类Class c = Class.forName("com.dailyblue.java.reflection.Student");// 获取对象Object obj = c.getDeclaredConstructor().newInstance();// 获取所有方法Method[] methods1 = c.getDeclaredMethods();Method[] methods2 = c.getMethods();System.out.println("---------------------------------");// 获取单个方法 第一个参数是方法名,其后参数是形式参数列表Method m1 = c.getDeclaredMethod("e", String.class);Method m2 = c.getDeclaredMethod("f");Method m3 = c.getMethod("d", Integer.TYPE, String.class);System.out.println("---------------------------------");// 操作方法 第一个参数是对象,其后参数是实际参数列表Object result1 = m1.invoke(obj, "admin");m2.setAccessible(true);Object result2 = m2.invoke(obj);Object result3 = m3.invoke(obj, 1, "张三");
invoke方法:作用:调用包装在当前Method对象中的方法。 原型:Object invoke(Object obj,Object...args) 参数解释:obj:实例化后的对象;args:用于方法调用的参数 返回:根据obj和args调用的方法的返回值 抛出错误:IllegalAccessException(Method对象强制Java语言执行控制或无权访问obj对象) IllegalArgumentException(方法是实例化方法,而指定需要调用的对象并不是实例化后的类或接口)