当前位置: 首页 > news >正文

【从0开始学习Java | 第22篇】反射

在这里插入图片描述

文章目录

  • Java反射:从基础到框架应用的实战指南
    • 一、反射介绍
      • 1. 什么是反射?
      • 2. 为什么需要反射?
    • 二、反射的核心:Class类
      • 1. 获取Class对象的三种方式
        • 方式1:通过 Class.forName(全类名)(运行时动态获取)
        • 方式2:通过 类名.class(编译期已知类)
        • 方式3:通过 对象.getClass()(已有实例)
    • 三、反射实战:操作类的结构
      • 1. 利用反射获取构造方法(Constuctor)
        • 使用的方法
        • 代码示例
      • 2. 利用反射获取成员变量(Field)
        • 使用的方法
        • 代码示例
      • 3. 调用方法(Method)
        • 使用的方法
        • 代码示例
    • 四、反射的应用场景
    • 五、反射的优缺点
      • 优点:
      • 缺点:

Java反射:从基础到框架应用的实战指南

一、反射介绍

1. 什么是反射?

简单来说,反射是Java提供的一种能力:允许程序在运行时获取类的详细信息(如属性、方法、构造器等),并动态操作这些信息

正常情况下,我们使用类的流程是“编译期确定类 → 实例化 → 调用方法”,比如:

User user = new User(); // 编译期已知User类
user.setName("张三");

而反射则是“运行时获取类信息 → 动态操作”,即使编译期不知道具体类名,也能通过字符串(如配置文件中的类路径)完成对象创建和方法调用。

在这里插入图片描述

2. 为什么需要反射?

举个实际开发中的例子:假设你需要开发一个工具,根据用户配置的类名创建对象。如果没有反射,只能硬编码判断:

// 配置文件中读取的类名
String className = "com.example.Student"; // 不使用反射:必须提前知道所有可能的类,扩展性极差
if (className.equals("com.example.User")) {return new User();
} else if (className.equals("com.example.Student")) {return new Student();
} else {// 新增类时必须修改代码
}

而有了反射,只需两行代码即可动态处理任意类:

Class<?> clazz = Class.forName(className); // 运行时加载类
Object obj = clazz.newInstance(); // 动态创建实例

这就是反射的核心价值:摆脱编译期的类型依赖,让程序更灵活、更具扩展性

二、反射的核心:Class类

反射的所有操作都围绕java.lang.Class类展开。每个类被JVM加载后,都会生成一个唯一的Class对象,它包含了该类的所有信息(属性、方法、构造器等)。可以说,Class对象是反射的“入口”。

1. 获取Class对象的三种方式

要使用反射,第一步是获取目标类的Class对象,常用三种方式:

方式1:通过 Class.forName(全类名)(运行时动态获取)

最常用的方式,通过类的全限定名(包名+类名)动态加载,适合从配置文件或数据库中读取类名的场景:

// 需处理ClassNotFoundException(类不存在时抛出)
Class<?> clazz = Class.forName("com.example.User"); 
方式2:通过 类名.class(编译期已知类)

如果编译期就知道具体类,直接通过类名.class获取,无需处理异常:

Class<User> userClass = User.class;
Class<String> stringClass = String.class;
方式3:通过 对象.getClass()(已有实例)

如果已有对象实例,调用其getClass()方法:

User user = new User();
Class<?> clazz = user.getClass(); // 此时clazz即为User类的Class对象

在这里插入图片描述

注意:Class.forName()会触发类的初始化(执行静态代码块),而后两种方式仅加载类不初始化。

三、反射实战:操作类的结构

我们以一个Student类为例,演示如何通过反射操作构造器、属性和方法:

import java.io.IOException;public class Student {private String name;private int age;public String gender;public Student() {}public Student(String name) {this.name = name;}protected Student(int age) {this.age = age;}private Student(String name, int age) {this.name = name;this.age = age;}public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", gender='" + gender + '\'' +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void sleep(){System.out.println("睡觉");}private void eat(String something) throws  IllegalAccessError , IOException {System.out.println("在吃"+something);}}

1. 利用反射获取构造方法(Constuctor)

通过反射调用构造器创建对象,支持无参和有参构造,包括私有构造器。

使用的方法

在这里插入图片描述

代码示例
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;public class MyReflect_Constructor {public static void main(String []args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {// 1.获取class字节码文件对象Class clazz = Class. forName("Student");// 2.获取所有公共构造方法Constructor[] cons = clazz.getConstructors();for(Constructor con : cons){System.out.println(con);}System.out.println("==============");// 获取所有构造方法,包括私有Constructor[]cons2 =   clazz.getDeclaredConstructors();for(Constructor con : cons2){System.out.println(con);}System.out.println("==============");Constructor con3 = clazz.getConstructor();System.out.println(con3);Constructor con4 = clazz.getDeclaredConstructor(int.class);System.out.println(con4);Constructor con5 = clazz.getConstructor(String.class);System.out.println(con5);Constructor con6 = clazz.getDeclaredConstructor(String.class,int.class);System.out.println(con6);// 获取权限修饰符int modifiers =  con6.getModifiers();System.out.println(modifiers);// 获取对应构造方法的所有参数Parameter[] parameters = con6.getParameters();for(Parameter parameter :parameters){System.out.println(parameter);}// 暴力反射:临时取消权限的校验 --> 利用私有构造方法创建对象con6.setAccessible(true);Student stu = (Student)con6.newInstance("林七夜",18);System.out.println(stu);}
}

运行结果:

public Student(java.lang.String)
public Student()
==============
private Student(java.lang.String,int)
protected Student(int)
public Student(java.lang.String)
public Student()
==============
public Student()
protected Student(int)
public Student(java.lang.String)
private Student(java.lang.String,int)
2
java.lang.String arg0
int arg1
Student@4554617c

方法区别:getConstructor()只能获取public构造器,getDeclaredConstructor()可获取所有权限的构造器。

2. 利用反射获取成员变量(Field)

反射可以获取类的所有属性(包括私有),并读写其值。

使用的方法

在这里插入图片描述

代码示例
import java.lang.reflect.Field;public class MyReflect_Field {public static void main(String []args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {// 1.获取class字节码文件的对象Class clazz = Class.forName("Student");// 2.获取成员变量// 公共的Field[] fields = clazz.getFields();for (Field field : fields) {System.out.println(field);}System.out.println("----------");// 所有的Field[] fields2 = clazz.getDeclaredFields();for (Field field : fields2) {System.out.println(field);}System.out.println("=========");// 3.获取单个成员变量// 私有Field name = clazz.getDeclaredField("name");System.out.println(name);System.out.println("---------");//公共Field gender = clazz.getField("gender");System.out.println(gender);// 4.获取权限修饰符int modifiers = name.getModifiers();System.out.println(modifiers);// 5.获取成员变量的名字String n = name.getName();System.out.println(n);// 6.获取成员变量的数据类型Class<?> type  = name.getType();System.out.println(type);// 7.获取成员变量记录的值Student s = new Student("张三",18,"男");name.setAccessible(true);String value = (String) name.get(s);System.out.println(value);// 8.修改对象里面的值name.set(s,"李四");System.out.println(s);}
}

3. 调用方法(Method)

反射可以调用类的任意方法(包括私有方法),支持传递参数。

使用的方法

在这里插入图片描述

代码示例
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;public class MyReflect_Method {public static void main(String []args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {// 1.获取class字节码文件对象Class clazz = Class.forName("Student");// 2.获取里面所有的方法对象(包含父类中的所有公共方法)Method[] methods = clazz.getMethods();for (Method method : methods) {System.out.println(method);}System.out.println("-------------");// 3. 获取子类的所有方法(不包括父类的,但包括本类的私有方法)Method[] methods2 = clazz.getDeclaredMethods();for (Method method : methods2) {System.out.println(method);}// 4.获取单一指定方法Method m = clazz.getDeclaredMethod("eat",String.class);System.out.println(m);// 5.获取方法的修饰符int modifiers = m.getModifiers();System.out.println(modifiers);// 6.获取方法的名字System.out.println(m.getName());// 7.获取方法的形参Parameter[] parameters = m.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter);}// 8.获取方法抛出的异常Class[] exceptionTypes = m.getExceptionTypes();for (Class exceptionType : exceptionTypes) {System.out.println(exceptionType);}// 9.Method类中用于创建对象的方法 (重点)Student s = new Student();m.setAccessible(true);// 参数一s:表示方法的调用者// 参数二"汉堡包":表示在调用方法是传递的实际参数m.invoke(s,"汉堡包");}
}

方法区别:getMethod()获取public方法,getDeclaredMethod()获取所有权限的方法;invoke()的第一个参数是实例(静态方法传null),后续参数是方法的实际参数。

四、反射的应用场景

反射的灵活性使其成为框架设计的核心,但日常业务开发中需谨慎使用(避免过度设计)。常见应用场景包括:

  1. 框架的IOC容器:如Spring通过反射根据配置文件创建Bean,实现“控制反转”;
  2. ORM框架:如MyBatis通过反射将数据库查询结果映射到Java对象的属性;
  3. 动态代理:AOP的实现依赖反射调用目标方法(如事务增强、日志记录);
  4. 注解解析:自定义注解(如@Controller@RequestMapping)的生效需要反射扫描并处理;
  5. 序列化/反序列化:JSON工具(如Jackson)通过反射将JSON字符串转换为Java对象。

五、反射的优缺点

优点:

  • 动态性:运行时操作类,适应灵活配置场景(如通过配置文件切换实现类);
  • 解耦:框架与业务类通过反射交互,无需硬编码依赖,降低耦合度;
  • 通用性:一套反射代码可处理任意类,提升工具类的复用性。

缺点:

  • 性能损耗:反射需要解析字节码,调用效率比直接调用低(但JVM已优化,非高频场景可忽略);
  • 安全风险setAccessible(true)会绕过访问权限检查,可能破坏类的封装性;
  • 可读性差:反射代码较抽象,调试和维护成本高于直接调用。

如果我的内容对你有帮助,请 点赞 评论 收藏 。创作不易,大家的支持就是我坚持下去的动力!

在这里插入图片描述

http://www.dtcms.com/a/502930.html

相关文章:

  • WEBSTORM前端 —— 第5章:Web APIs —— 第1节:Dom获取属性操作
  • 第 167 场双周赛 / 第 471 场周赛
  • 聊聊 Unity(小白专享、C# 小程序 之 加密存储)
  • 如何推销网站分销商城开发多少钱
  • 大型的营销型网站建设做国外网站翻译中国小说赚钱
  • 论文学习_PalmTree: Learning an Assembly Language Model for Instruction Embedding
  • 基于PSO-BP粒子群优化神经网络+NSGAII多目标优化算法的工艺参数优化、工程设计优化(三个输出目标案例)!(Matlab源码和数据)
  • 端到端与世界模型(2):基于认知驱动的自动驾驶3.0
  • [嵌入式系统-143]:自动驾驶汽车与智能机器人的操作系统
  • Python设计模式 - 外观模式
  • [排序算法]希尔排序
  • 做网站应该用多少分辨率西安高端网站建设首选
  • FFmpeg 基本API avcodec_receive_frame函数内部调用流程分析
  • FFmpeg 基本API av_read_frame函数内部调用流程分析
  • 广东网站建设包括什么口碑好网站建设是哪家
  • 和田地区建设局网站电子商务网络营销是干嘛的
  • SAP B1实施专家指南:如何优化成本与缩短项目周期?
  • [吾爱大神原创工具] Python多功能自动化点击录入工具V1.0
  • 不备案怎么做淘宝客网站wordpress 字体调整
  • 栈及相关算法问题
  • Docker镜像分层与写时复制原理详解
  • 药物靶点研究3天入门|Day1:从疾病差异里挖“潜力靶点”,两步锁定真目标
  • WebForms ArrayList详解
  • 达梦数据库性能调优总结
  • [JavaEE初阶]HTTPS-SSL传输过程中的加密
  • 单片机开发中裸机系统有哪些(轮询、时间片、前后台.....)
  • 一次线上MySQL分页事故,搞了半夜...
  • 医院网站建设思路深圳展览设计公司
  • C#WPF关键类
  • 从文件加密到数据料理台:两款主流加密工具(EncFSMP/CyberChef)技术特性解析与开发实战选型