1. 概念:
- 反射主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
- 反射机制的作用
- 在运行时判断任意一个对象所属的类
- 在运行时获取类的对象
- 在运行时访问java对象的属性、方法、构造方法等
- java.lang.reflect类库里面主要的类
- Field 表示类中的成员变量
- Method 表示类中的方法
- Constructor 表示类的构造方法
- Array 该类提供了动态创建数组和访问数组元素的静态方法
- 反射依赖的Class 用来表示运行时类型信息的对应类
- 每个类都有唯一一个与之相对应的Class对象
- Class类为类类型,而Class对象为类类型对象
- Class类的特点
- Class类也是类的一种,class则是关键字
- Class类只有一个私有的构造函数,只有JVM能够创建Class类的实例
- JVM中只有唯一一个和类相对应的Class对象来描述其类型信息
- 获取Class对象的三种方式
- Object -> getClass()
- 任何数据类型(包括基本数据类型)都有一个"静态"的class属性
- 通过Class类的静态方法:forName(String className)(常用)
- 在运行期间,一个类只有一个与之相对应的Class对象产生
- Class对象就像一面镜子,透过这面镜子可以看到类的结构
2. 反射的主要用法
- 如何获取类的构造方法并使用
/** * 通过Class对象可以获取某个类中的:构造方法 * * 获取构造方法: * 1. 批量的方法 * public Constructor[] getConstructors() 所有"公有的"构造方法 * public Constructor[] getDeclaredConstructors() 获取所有的构造方法(包括私有 受保护 默认 公有) * 2. 获取单个的方法并调用 * public Constructor getConstructor(Class... parameterTypes) 获取单个的"公有的"构造方法 * public Constructor getDeclaredConstructor(Class... parameterTypes) 获取"某个构造方法"可以私有 受保护 默认 公有 * * 调用构造方法: * Constructor -> newInstance(Object... initargs) */ public class ConstructorCollector { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class clazz = Class.forName("demo.reflect.ReflectTarget"); // 1. 获取所有的公有构造方法 System.out.println("************************所有公有构造方法************************"); Constructor[] conArray = clazz.getConstructors(); for(Constructor c : conArray) { System.out.println(c); } // 2. 获取所有构造方法 System.out.println("*********所有的构造方法(包括私有 受保护 默认 公有)*********"); conArray = clazz.getDeclaredConstructors(); for(Constructor c : conArray) { System.out.println(c); } // 3. 获取单个带参的公有方法 System.out.println("*********获取公有、有两个参数的构造方法*********"); Constructor con = clazz.getConstructor(String.class, int.class); System.out.println("con = " + con); // 4. 获取单个私有的构造方法 System.out.println("*********获取私有构造方法*********"); con = clazz.getDeclaredConstructor(int.class); System.out.println("private con = " + con); System.out.println("*********调用私有构造方法创建实例*********"); // 暴力访问(忽略访问修饰符) con.setAccessible(true); ReflectTarget reflectTarget = (ReflectTarget) con.newInstance(1); } }
public class ReflectTarget { //-----------构造函数----------- // (默认的带参构造函数) ReflectTarget(String str) { System.out.println("(默认)的构造方法s = " + str); } // 无参构造函数 public ReflectTarget() { System.out.println("调用了公有的无参构造方法..."); } // 有一个参数的构造函数 public ReflectTarget(char name) { System.out.println("调用了带有一个参数的构造方法,参数值为 " + name); } // 有多个参数的构造函数 public ReflectTarget(String name, int index) { System.out.println("调用了带有多个参数的构造方法,参数值为【目标名】: " + name + "【序号】" + index); } // 受保护的构造函数 protected ReflectTarget(boolean n) { System.out.println("受保护的构造方法n:" + n); } // 私有的构造函数 private ReflectTarget(int index) { System.out.println("私有的构造方法 序号:" + index); } }
- 如何获取类的成员变量并使用
/** * 获取成员变量并调用: * * 1. 批量的 * 1). Field[] getFields() 获取所有的"公有字段" * 2). Field[] getDeclaredFields() 获取所有字段,包括私有 受保护 默认 公有 * 2. 获取单个的 * 1). public Field getField(String fieldName) 获取某个"公有的"字段 * 2). public Field getDeclaredField(String fieldName) 获取某个字段(可以是私有的) * * 设置字段的值: * Field -> public void set(Object obj, Object value) * 参数说明: * 1. obj:要设置的字段所在的对象 * 2. value:要为字段设置的值 */ public class FieldCollector { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 获取Class对象 Class reflectTargetClass = Class.forName("demo.reflect.ReflectTarget"); // 1. 获取所有公有的字段 System.out.println("*********获取所有公有的字段*********"); Field[] fieldArray = reflectTargetClass.getFields(); for(Field f : fieldArray) { System.out.println(f); } // 2. 获取所有的字段 System.out.println("*********获取所有的字段(包括私有 受保护 默认)*********"); fieldArray = reflectTargetClass.getDeclaredFields(); for(Field f : fieldArray) { System.out.println(f); } // 3. 获取单个特定公有的field System.out.println("*********获取公有字段并调用*********"); Field f = reflectTargetClass.getField("name"); System.out.println("公有的field name: " + f); ReflectTarget reflectTarget = (ReflectTarget) reflectTargetClass.getConstructor().newInstance(); // 4. 给获取到的field赋值 f.set(reflectTarget, "待反射一号"); // 5. 验证对应的值name System.out.println("验证name:" + reflectTarget.name); // 6. 获取单个私有的Field System.out.println("*********获取私有字段targetInfo并调用*********"); f = reflectTargetClass.getDeclaredField("targetInfo"); f.setAccessible(true); System.out.println(f); f.set(reflectTarget, "13810592345"); System.out.println("验证信息:" + reflectTarget); } }
public class ReflectTarget extends ReflectTargetOrigin { //-----------构造函数----------- // (默认的带参构造函数) ReflectTarget(String str) { System.out.println("(默认)的构造方法s = " + str); } // 无参构造函数 public ReflectTarget() { System.out.println("调用了公有的无参构造方法..."); } // 有一个参数的构造函数 public ReflectTarget(char name) { System.out.println("调用了带有一个参数的构造方法,参数值为 " + name); } // 有多个参数的构造函数 public ReflectTarget(String name, int index) { System.out.println("调用了带有多个参数的构造方法,参数值为【目标名】: " + name + "【序号】" + index); } // 受保护的构造函数 protected ReflectTarget(boolean n) { System.out.println("受保护的构造方法n:" + n); } // 私有的构造函数 private ReflectTarget(int index) { System.out.println("私有的构造方法 序号:" + index); } //-----------字段----------- public String name; protected int index; char type; private String targetInfo; @Override public String toString() { return "ReflectTarget{" + "name='" + name + '\'' + ", index=" + index + ", type=" + type + ", targetInfo='" + targetInfo + '\'' + '}'; } }
public class ReflectTargetOrigin { String defaultMember = "default"; public String publicMember = "public"; protected String protectedMember = "protected"; private String privateMember = "private"; }
- 如何获取类的成员方法并使用
/** * 获取成员方法并调用 * 1. 批量的 * public Method[] getMethods() 获取所有"公有方法";(包含了父类的方法也包含Object类) * public Method[] getDeclaredMethods() 获取所有的成员方法,包括私有的(不包括继承的) * 2. 获取单个的 * public Method getMethod(String name, Class<?>... parameterTypes) * 参数: * name:方法名 * Class...:形参的Class类型对象 * public Method getDeclaredMethod(String name, Class<?>... parameterTypes) * * 调用方法: * Method -> public Object invoke(Object obj, Object... args) * 参数说明: * obj:要调用方法的对象 * args:调用方法时所传递的实参 */ public class MethodCollector { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 1. 获取Class对象 Class reflectTargetClass = Class.forName("demo.reflect.ReflectTarget"); // 2. 获取所有公有方法 System.out.println("**********获取所有的public方法,包括父类和Object**********"); Method[] methodArray = reflectTargetClass.getMethods(); for(Method m : methodArray) { System.out.println(m); } // 3. 获取该类的所有方法 System.out.println("**********获取所有的方法,包括私有的**********"); methodArray = reflectTargetClass.getDeclaredMethods(); for (Method m : methodArray) { System.out.println(m); } // 4. 获取单个公有方法 Method m = reflectTargetClass.getMethod("show1", String.class); System.out.println(m); // 5. 调用show1并执行 ReflectTarget reflectTarget = (ReflectTarget) reflectTargetClass.getConstructor().newInstance(); m.invoke(reflectTarget, "待反射方法一号"); // 6. 获取一个私有的成员方法 System.out.println("**********获取私有的show4()方法**********"); m = reflectTargetClass.getDeclaredMethod("show4", int.class); System.out.println(m); m.setAccessible(true); String result = String.valueOf(m.invoke(reflectTarget, 20)); System.out.println("返回值:" + result); } }
public class ReflectTarget extends ReflectTargetOrigin { //-----------构造函数----------- // (默认的带参构造函数) ReflectTarget(String str) { System.out.println("(默认)的构造方法s = " + str); } // 无参构造函数 public ReflectTarget() { System.out.println("调用了公有的无参构造方法..."); } // 有一个参数的构造函数 public ReflectTarget(char name) { System.out.println("调用了带有一个参数的构造方法,参数值为 " + name); } // 有多个参数的构造函数 public ReflectTarget(String name, int index) { System.out.println("调用了带有多个参数的构造方法,参数值为【目标名】: " + name + "【序号】" + index); } // 受保护的构造函数 protected ReflectTarget(boolean n) { System.out.println("受保护的构造方法n:" + n); } // 私有的构造函数 private ReflectTarget(int index) { System.out.println("私有的构造方法 序号:" + index); } //-----------字段----------- public String name; protected int index; char type; private String targetInfo; @Override public String toString() { return "ReflectTarget{" + "name='" + name + '\'' + ", index=" + index + ", type=" + type + ", targetInfo='" + targetInfo + '\'' + '}'; } //-----------成员方法----------- public void show1(String s) { System.out.println("调用了公有的,String参数的show1(): s = " + s); } protected void show2() { System.out.println("调用了受保护的,无参的show2()"); } void show3() { System.out.println("调用了默认的,无参的show3()"); } private String show4(int index) { System.out.println("调用了私有的,并且有返回值的,int参数的show4:index = " + index); return "show4result"; } }