一、反射到底是什么一句话讲透核心本质在正式敲代码前我们先把反射的本质掰碎了讲明白这是学好反射的第一步先给大家一个最通俗的定义反射就是 Java 在程序运行时能 “解剖” 一个类的技术不管这个类是 public 还是 private不管你知不知道它的具体类型只要拿到它的Class 对象反射就能帮你拿到这个类的构造方法无参、有参、私有都能拿拿到这个类的成员变量public、private、protected 全能获取拿到这个类的成员方法公开方法、私有方法、静态方法全能调用甚至能动态创建对象、动态赋值、动态执行方法再简单点总结正常写代码先知道类名→创建对象→调用方法反射写代码运行时才知道类名→动态拿构造→动态创对象→动态执行方法这就是反射最大的魅力 ——动态性也是所有框架能实现 “自动装配、依赖注入、注解解析” 的底层根基。而反射的唯一核心就是Class 对象 所有反射操作第一步必须先获取 Class 对象没有它反射寸步难行二、反射入门第一步获取 Class 对象的 3 种方式必考一切反射的起点都是获取Class对象 Java 给我们提供了3 种标准方式每一种都有固定使用场景面试必问、开发必用方式 1Class.forName (全类名) —— 最常用、框架最爱这是开发和框架中使用最多的方式也是动态性最强的方式 只需要传入类的全限定名包名 类名就能在运行时加载类生成 Class 对象。// 写法Class.forName(完整包名类名) Class? clazz Class.forName(com.example.demo.Student);核心特点运行时动态加载类解耦极强不需要导入类不需要创建对象只需要字符串Spring、MyBatis、JDBC 全用这种方式加载类方式 2对象名.getClass () —— 已有对象时用如果你已经创建了这个类的对象想通过对象反向获取 Class 对象就用这种方式// 先创建对象 Student student new Student(); // 通过对象获取Class Class? extends Student clazz student.getClass();核心特点必须先有对象才能调用多用于方法参数是对象时动态获取类型方式 3类名.class —— 明确知道类名时用如果你明确知道要操作的类名直接用类名点 class最简单粗暴// 直接通过类名获取 ClassStudent clazz Student.class;核心特点代码最简单最安全编译期就确定类型没有异常适合写死类名的场景高频易错点提醒90% 的人都错过很多同学会写错// 错误写法 对象名.class; // 正确写法 对象名.getClass();对象只能调用 getClass () 方法不能用.class 属性.class 是类的属性不是对象的三、3 种获取 Class 方式的真实使用场景实战必懂光会写代码没用你得知道什么时候用哪种方式这才是真正掌握反射场景 1读取配置文件 → 必须用 Class.forName ()这是框架最核心的使用场景 比如 JDBC 驱动加载、Spring 读取 bean 配置、MyBatis 加载 Mapper全是这种用法。举个实战例子在 src 目录下创建配置文件bean.properties# 配置类的全路径 classNamecom.example.demo.Student主程序读取配置动态加载类// 1.创建Properties读取配置 Properties prop new Properties(); // 2.读取配置文件 prop.load(Main.class.getClassLoader().getResourceAsStream(bean.properties)); // 3.获取配置的类名 String className prop.getProperty(className); // 4.动态加载Class对象核心 Class? clazz Class.forName(className);优势改配置不用改代码完全解耦场景 2方法参数是对象 → 用 对象.getClass ()当你在方法里接收一个对象想获取它的 Class就用这种方式// 形参是对象 public void getObjectClass(Student stu){ // 通过对象获取Class Class? extends Student clazz stu.getClass(); }场景 3明确知道类名 → 直接用 类名.class比如你就是要操作 Student 类直接写ClassStudent clazz Student.class;如果在类内部还可以用this.getClass()替代四、反射实战第一弹动态获取构造器创建对象学会获取 Class 对象后第一个实战操作用反射创建对象 不管是无参、有参、私有构造反射全能搞定核心 APIConstructor 构造器对象获取 public 构造器// 获取public无参构造 clazz.getConstructor(); // 获取public有参构造指定参数类型 clazz.getConstructor(String.class, int.class);获取任意权限构造器包含私有// 获取所有构造器public/private都可以 clazz.getDeclaredConstructor();通过构造器创建对象构造器对象.newInstance(参数);实战准备先创建一个 Student 实体类我们用 Lombok 简化代码方便测试import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; Data NoArgsConstructor AllArgsConstructor public class Student { // 私有成员变量 private String name; private int age; }案例 1反射调用 public 无参构造创建对象public class ReflectTest { public static void main(String[] args) throws Exception { // 1.获取Class对象 ClassStudent clazz Student.class; // 2.获取无参构造器 ConstructorStudent constructor clazz.getConstructor(); // 3.通过构造器创建对象 Student student constructor.newInstance(); // 4.赋值测试 student.setName(张三); student.setAge(18); System.out.println(student); } }案例 2反射调用 public 有参构造创建对象public static void main(String[] args) throws Exception { // 1.获取Class ClassStudent clazz Student.class; // 2.获取有参构造Stringint ConstructorStudent constructor clazz.getConstructor(String.class, int.class); // 3.传入参数创建对象 Student student constructor.newInstance(李四, 20); System.out.println(student); }案例 3暴力反射 —— 调用私有构造器重点如果构造方法是private的正常代码根本用不了但反射可以暴力破解 只需要一行代码setAccessible(true)public static void main(String[] args) throws Exception { ClassStudent clazz Student.class; // 1.获取私有构造器用Declared ConstructorStudent constructor clazz.getDeclaredConstructor(); // 2.暴力反射关闭权限检查 constructor.setAccessible(true); // 3.创建对象 Student student constructor.newInstance(); System.out.println(student); }这就是反射的强大之处无视权限五、反射实战第二弹动态操作成员变量Field不管成员变量是 public 还是 private反射都能获取值、修改值核心 API 区分必背getField(变量名)只能获取 public 变量getDeclaredField(变量名)获取所有权限变量private 首选核心操作方法// 1.暴力破解私有变量必须加 field.setAccessible(true); // 2.给对象的变量赋值 field.set(对象, 值); // 3.获取对象的变量值 field.get(对象);实战案例反射操作私有成员变量public static void main(String[] args) throws Exception { // 1.获取Class ClassStudent clazz Student.class; // 2.获取私有成员变量 name必须用Declared Field nameField clazz.getDeclaredField(name); // 3.暴力反射 nameField.setAccessible(true); // 4.创建空对象 Student student clazz.newInstance(); // 5.给私有变量赋值 nameField.set(student, 反射修改变量); // 6.获取变量值 String name (String) nameField.get(student); System.out.println(获取到的名字 name); }运行结果获取到的名字反射修改变量正常代码无法访问 private 变量但反射轻松搞定Spring 依赖注入就是这么实现的六、反射实战第三弹动态调用成员方法Method这是反射最常用、最核心的功能 不管是 public 方法、private 方法、有参方法、无参方法反射都能动态执行核心 API 区分getMethod(方法名, 参数类型)只能获取 public 方法getDeclaredMethod(方法名, 参数类型)获取所有权限方法核心执行方法// 破解私有方法 method.setAccessible(true); // 执行方法invoke(对象, 方法参数) method.invoke(对象, 参数...);案例 1反射调用 public 的 get/set 方法public static void main(String[] args) throws Exception { // 1.获取Class ClassStudent clazz Student.class; Student student clazz.newInstance(); // 2.获取setName方法参数是String Method setNameMethod clazz.getMethod(setName, String.class); // 3.执行方法给student对象赋值 setNameMethod.invoke(student, 反射调用方法); // 4.获取getName方法并执行 Method getNameMethod clazz.getMethod(getName); String name (String) getNameMethod.invoke(student); System.out.println(执行getName结果 name); }案例 2反射调用私有方法暴力反射如果方法是private的照样能调用// 1.获取私有方法 Method privateMethod clazz.getDeclaredMethod(私有方法名); // 2.暴力破解 privateMethod.setAccessible(true); // 3.执行方法 privateMethod.invoke(student);Spring 的注解驱动、AOP、事务管理底层全靠这个 invoke 方法七、反射核心必背规则面试 考试高频这些知识点是面试官最爱问的也是写反射代码不报错的关键必须背下来getXXX () 只能获取 public 权限构造器、变量、方法只要带Field/Method/Constructor都只能拿 public 的。getDeclaredXXX () 能获取所有权限private、默认、protected、public全能获取开发首选 Declared 系列操作私有资源必须加 setAccessible (true)不加这行代码直接报IllegalAccessException权限异常反射所有 API 都抛出编译时异常代码必须try-catch或者throws抛出否则无法运行。Class.forName () 是框架解耦神器配置文件 forName实现无代码侵入Spring 核心用法。反射最大特点运行时动态操作编译期不知道类型运行时才确定这是框架的灵魂。八、反射所有核心 API 终极汇总一张表搞定我把反射所有常用 API 整理成速查表开发、面试直接对照用1. Class 类核心方法方法功能API 方法获取 public 无参构造getConstructor()获取 public 有参构造getConstructor (参数类型...)获取任意构造getDeclaredConstructor (参数类型...)获取 public 成员变量getField (变量名)获取任意成员变量getDeclaredField (变量名)获取 public 成员方法getMethod (方法名参数类型)获取任意成员方法getDeclaredMethod (方法名参数类型)快速创建对象newInstance()2. Constructor 构造器对象方法作用newInstance()创建对象setAccessible(true)暴力破解私有构造3. Field 成员变量对象方法作用set (对象值)给变量赋值get (对象)获取变量值setAccessible(true)破解私有变量4. Method 成员方法对象方法作用invoke (对象参数)执行方法setAccessible(true)破解私有方法九、反射到底有什么用不学框架就没用吗很多同学会问我平时写业务代码好像用不上反射啊大错特错你不用反射但你天天在用的工具全是反射写的反射的核心应用场景Spring 框架IOC 容器创建对象、依赖注入、注解解析MyBatisMapper 接口动态代理、参数赋值、结果封装SpringBoot自动配置、类路径扫描、动态加载组件JDBC加载数据库驱动动态代理JDK 动态代理底层就是反射通用工具类对象拷贝、属性赋值、注解校验可以说没有反射就没有现在的 Java 生态十、全文总结反射核心一句话复盘最后帮大家用最简单的话复盘整篇文章的核心反射 运行时解剖类动态操作构造、变量、方法一切反射从 Class 对象开始3 种获取方式牢记场景getXXX 拿 publicgetDeclared 拿全部私有资源必须暴力反射setAccessible (true)构造器创建对象Field 赋值Method 执行方法反射是框架底层核心不学反射看不懂源码
全网最通俗易懂 Java 反射精讲!从入门到框架底层,一篇吃透反射核心
一、反射到底是什么一句话讲透核心本质在正式敲代码前我们先把反射的本质掰碎了讲明白这是学好反射的第一步先给大家一个最通俗的定义反射就是 Java 在程序运行时能 “解剖” 一个类的技术不管这个类是 public 还是 private不管你知不知道它的具体类型只要拿到它的Class 对象反射就能帮你拿到这个类的构造方法无参、有参、私有都能拿拿到这个类的成员变量public、private、protected 全能获取拿到这个类的成员方法公开方法、私有方法、静态方法全能调用甚至能动态创建对象、动态赋值、动态执行方法再简单点总结正常写代码先知道类名→创建对象→调用方法反射写代码运行时才知道类名→动态拿构造→动态创对象→动态执行方法这就是反射最大的魅力 ——动态性也是所有框架能实现 “自动装配、依赖注入、注解解析” 的底层根基。而反射的唯一核心就是Class 对象 所有反射操作第一步必须先获取 Class 对象没有它反射寸步难行二、反射入门第一步获取 Class 对象的 3 种方式必考一切反射的起点都是获取Class对象 Java 给我们提供了3 种标准方式每一种都有固定使用场景面试必问、开发必用方式 1Class.forName (全类名) —— 最常用、框架最爱这是开发和框架中使用最多的方式也是动态性最强的方式 只需要传入类的全限定名包名 类名就能在运行时加载类生成 Class 对象。// 写法Class.forName(完整包名类名) Class? clazz Class.forName(com.example.demo.Student);核心特点运行时动态加载类解耦极强不需要导入类不需要创建对象只需要字符串Spring、MyBatis、JDBC 全用这种方式加载类方式 2对象名.getClass () —— 已有对象时用如果你已经创建了这个类的对象想通过对象反向获取 Class 对象就用这种方式// 先创建对象 Student student new Student(); // 通过对象获取Class Class? extends Student clazz student.getClass();核心特点必须先有对象才能调用多用于方法参数是对象时动态获取类型方式 3类名.class —— 明确知道类名时用如果你明确知道要操作的类名直接用类名点 class最简单粗暴// 直接通过类名获取 ClassStudent clazz Student.class;核心特点代码最简单最安全编译期就确定类型没有异常适合写死类名的场景高频易错点提醒90% 的人都错过很多同学会写错// 错误写法 对象名.class; // 正确写法 对象名.getClass();对象只能调用 getClass () 方法不能用.class 属性.class 是类的属性不是对象的三、3 种获取 Class 方式的真实使用场景实战必懂光会写代码没用你得知道什么时候用哪种方式这才是真正掌握反射场景 1读取配置文件 → 必须用 Class.forName ()这是框架最核心的使用场景 比如 JDBC 驱动加载、Spring 读取 bean 配置、MyBatis 加载 Mapper全是这种用法。举个实战例子在 src 目录下创建配置文件bean.properties# 配置类的全路径 classNamecom.example.demo.Student主程序读取配置动态加载类// 1.创建Properties读取配置 Properties prop new Properties(); // 2.读取配置文件 prop.load(Main.class.getClassLoader().getResourceAsStream(bean.properties)); // 3.获取配置的类名 String className prop.getProperty(className); // 4.动态加载Class对象核心 Class? clazz Class.forName(className);优势改配置不用改代码完全解耦场景 2方法参数是对象 → 用 对象.getClass ()当你在方法里接收一个对象想获取它的 Class就用这种方式// 形参是对象 public void getObjectClass(Student stu){ // 通过对象获取Class Class? extends Student clazz stu.getClass(); }场景 3明确知道类名 → 直接用 类名.class比如你就是要操作 Student 类直接写ClassStudent clazz Student.class;如果在类内部还可以用this.getClass()替代四、反射实战第一弹动态获取构造器创建对象学会获取 Class 对象后第一个实战操作用反射创建对象 不管是无参、有参、私有构造反射全能搞定核心 APIConstructor 构造器对象获取 public 构造器// 获取public无参构造 clazz.getConstructor(); // 获取public有参构造指定参数类型 clazz.getConstructor(String.class, int.class);获取任意权限构造器包含私有// 获取所有构造器public/private都可以 clazz.getDeclaredConstructor();通过构造器创建对象构造器对象.newInstance(参数);实战准备先创建一个 Student 实体类我们用 Lombok 简化代码方便测试import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; Data NoArgsConstructor AllArgsConstructor public class Student { // 私有成员变量 private String name; private int age; }案例 1反射调用 public 无参构造创建对象public class ReflectTest { public static void main(String[] args) throws Exception { // 1.获取Class对象 ClassStudent clazz Student.class; // 2.获取无参构造器 ConstructorStudent constructor clazz.getConstructor(); // 3.通过构造器创建对象 Student student constructor.newInstance(); // 4.赋值测试 student.setName(张三); student.setAge(18); System.out.println(student); } }案例 2反射调用 public 有参构造创建对象public static void main(String[] args) throws Exception { // 1.获取Class ClassStudent clazz Student.class; // 2.获取有参构造Stringint ConstructorStudent constructor clazz.getConstructor(String.class, int.class); // 3.传入参数创建对象 Student student constructor.newInstance(李四, 20); System.out.println(student); }案例 3暴力反射 —— 调用私有构造器重点如果构造方法是private的正常代码根本用不了但反射可以暴力破解 只需要一行代码setAccessible(true)public static void main(String[] args) throws Exception { ClassStudent clazz Student.class; // 1.获取私有构造器用Declared ConstructorStudent constructor clazz.getDeclaredConstructor(); // 2.暴力反射关闭权限检查 constructor.setAccessible(true); // 3.创建对象 Student student constructor.newInstance(); System.out.println(student); }这就是反射的强大之处无视权限五、反射实战第二弹动态操作成员变量Field不管成员变量是 public 还是 private反射都能获取值、修改值核心 API 区分必背getField(变量名)只能获取 public 变量getDeclaredField(变量名)获取所有权限变量private 首选核心操作方法// 1.暴力破解私有变量必须加 field.setAccessible(true); // 2.给对象的变量赋值 field.set(对象, 值); // 3.获取对象的变量值 field.get(对象);实战案例反射操作私有成员变量public static void main(String[] args) throws Exception { // 1.获取Class ClassStudent clazz Student.class; // 2.获取私有成员变量 name必须用Declared Field nameField clazz.getDeclaredField(name); // 3.暴力反射 nameField.setAccessible(true); // 4.创建空对象 Student student clazz.newInstance(); // 5.给私有变量赋值 nameField.set(student, 反射修改变量); // 6.获取变量值 String name (String) nameField.get(student); System.out.println(获取到的名字 name); }运行结果获取到的名字反射修改变量正常代码无法访问 private 变量但反射轻松搞定Spring 依赖注入就是这么实现的六、反射实战第三弹动态调用成员方法Method这是反射最常用、最核心的功能 不管是 public 方法、private 方法、有参方法、无参方法反射都能动态执行核心 API 区分getMethod(方法名, 参数类型)只能获取 public 方法getDeclaredMethod(方法名, 参数类型)获取所有权限方法核心执行方法// 破解私有方法 method.setAccessible(true); // 执行方法invoke(对象, 方法参数) method.invoke(对象, 参数...);案例 1反射调用 public 的 get/set 方法public static void main(String[] args) throws Exception { // 1.获取Class ClassStudent clazz Student.class; Student student clazz.newInstance(); // 2.获取setName方法参数是String Method setNameMethod clazz.getMethod(setName, String.class); // 3.执行方法给student对象赋值 setNameMethod.invoke(student, 反射调用方法); // 4.获取getName方法并执行 Method getNameMethod clazz.getMethod(getName); String name (String) getNameMethod.invoke(student); System.out.println(执行getName结果 name); }案例 2反射调用私有方法暴力反射如果方法是private的照样能调用// 1.获取私有方法 Method privateMethod clazz.getDeclaredMethod(私有方法名); // 2.暴力破解 privateMethod.setAccessible(true); // 3.执行方法 privateMethod.invoke(student);Spring 的注解驱动、AOP、事务管理底层全靠这个 invoke 方法七、反射核心必背规则面试 考试高频这些知识点是面试官最爱问的也是写反射代码不报错的关键必须背下来getXXX () 只能获取 public 权限构造器、变量、方法只要带Field/Method/Constructor都只能拿 public 的。getDeclaredXXX () 能获取所有权限private、默认、protected、public全能获取开发首选 Declared 系列操作私有资源必须加 setAccessible (true)不加这行代码直接报IllegalAccessException权限异常反射所有 API 都抛出编译时异常代码必须try-catch或者throws抛出否则无法运行。Class.forName () 是框架解耦神器配置文件 forName实现无代码侵入Spring 核心用法。反射最大特点运行时动态操作编译期不知道类型运行时才确定这是框架的灵魂。八、反射所有核心 API 终极汇总一张表搞定我把反射所有常用 API 整理成速查表开发、面试直接对照用1. Class 类核心方法方法功能API 方法获取 public 无参构造getConstructor()获取 public 有参构造getConstructor (参数类型...)获取任意构造getDeclaredConstructor (参数类型...)获取 public 成员变量getField (变量名)获取任意成员变量getDeclaredField (变量名)获取 public 成员方法getMethod (方法名参数类型)获取任意成员方法getDeclaredMethod (方法名参数类型)快速创建对象newInstance()2. Constructor 构造器对象方法作用newInstance()创建对象setAccessible(true)暴力破解私有构造3. Field 成员变量对象方法作用set (对象值)给变量赋值get (对象)获取变量值setAccessible(true)破解私有变量4. Method 成员方法对象方法作用invoke (对象参数)执行方法setAccessible(true)破解私有方法九、反射到底有什么用不学框架就没用吗很多同学会问我平时写业务代码好像用不上反射啊大错特错你不用反射但你天天在用的工具全是反射写的反射的核心应用场景Spring 框架IOC 容器创建对象、依赖注入、注解解析MyBatisMapper 接口动态代理、参数赋值、结果封装SpringBoot自动配置、类路径扫描、动态加载组件JDBC加载数据库驱动动态代理JDK 动态代理底层就是反射通用工具类对象拷贝、属性赋值、注解校验可以说没有反射就没有现在的 Java 生态十、全文总结反射核心一句话复盘最后帮大家用最简单的话复盘整篇文章的核心反射 运行时解剖类动态操作构造、变量、方法一切反射从 Class 对象开始3 种获取方式牢记场景getXXX 拿 publicgetDeclared 拿全部私有资源必须暴力反射setAccessible (true)构造器创建对象Field 赋值Method 执行方法反射是框架底层核心不学反射看不懂源码