当前位置: 首页 > 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;
}
@Override
public 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对象。

五、反射的优缺点

优点:

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

缺点:


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

在这里插入图片描述

http://www.gsyq.cn/news/49806.html

相关文章:

  • 【题解】LOJ6300. 「CodePlus 2018 3 月赛」博弈论与概率统计
  • C#循序渐进 - 详解
  • 2025.11.14 - A
  • 从RvmTranslator到PlantAssistant
  • PortSwigger靶场之 CSRF where token is not tied to user session通关秘籍 - 实践
  • 【HT-086-Div.2】嗡嗡蜜蜂
  • 第四十一篇
  • 好题集 (0) - 目录
  • 2025年成绩差的孩子该用学习机吗?松鼠AI双线模式测评及选购指南
  • CF 1844G Tree Weights
  • Vue3边学边做系列(5)--布局切换菜单事件标签页 - 实践
  • 2025年11月徐州网站建设服务商综合评测与选择指南
  • 2025年11月眉笔选购指南:花西子/植村秀/珂拉琪等5大品牌实测,新手闭眼入款竟是它​
  • Upcoming Rust language features for kernel development - 教程
  • 详细介绍:Linux网络性能测试利器:iperf3使用指南
  • linux 安装telnet 服务
  • 2025高压合金管实力厂家推荐榜:5310/6479 高压合金管型号领衔,天津大无缝联合钢铁有限公司五星领跑工业用材赛道
  • 2025扫描电镜精选榜:富泰微五星领衔,日立、国仪携超高分辨率/钨灯丝 SEM,适配科研工业多元需求
  • 2025济南单招综评培训机构排行榜:3 家实力学校口碑出圈 易升教育五星优选 解锁适配不同考生的升学备考靠谱路径
  • 102302141_易敏亮第三次数据采集作业
  • 2025广东洗头机厂家推荐榜:盛泰科技领衔,三大品牌解锁高效洗护新体验
  • mysql数据设计中的性能分析工具
  • 2025北京日式搬家公司企业推荐:单位搬家公司/北京搬家公司电话/全流程服务与技术实力深度解析
  • 2025年第43周数字取证与事件响应技术动态
  • 深入解析:【Linux基础学习】Linux Ubuntu 权限管理:从入门到精通
  • 看不见的核安全:核控制系统如何降低测试风险?
  • 2025 最新护栏网厂家推荐排行榜,公路铁路 / 机场 / 市政工程优质厂家实力甄选铁路护栏网/勾花护栏网/机场护栏网公司推荐
  • 2025 年石笼网厂家最新推荐排行榜:箱形 / 网垫 / 袋形 / 帘形全品类,电镀锌 / 锌铝合金 / 电焊材质优质厂家权威推荐
  • spark热点key导致的数据倾斜复现和加盐处理 - 指南
  • Netty和Tomcat