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

Java 进阶:反射机制深度解析

Java-day19

一、反射机制概述:什么是 Java 反射?

1.1 反射的定义

Java 反射是指程序在**运行时**可以**获取类的所有信息**(包括接口、父类、构造器、方法、变量等),并可以动态操作类的成员(如创建对象、调用方法、修改变量)的能力。

简单来说,反射让 Java 程序具备了“**自我检查**”和“**动态操作**”的特性,是 Java 实现“元编程”的核心机制。

1.2 反射的应用场景

- 框架开发(如 Spring、MyBatis):通过反射实现组件的自动装配、SQL 语句与方法的映射等;

- 动态代理:在运行时生成代理类,实现 AOP(面向切面编程);

- 类信息检查:在工具类中获取类的结构信息(如 IDE 的“查看类结构”功能)。

二、反射的原理:类加载与 Class 对象

2.1 类的加载过程

Java 类的生命周期分为三个阶段:

- **磁盘文件阶段**:类以 .java 源文件或 .class 字节码文件的形式存储在磁盘;

- **类对象阶段**:编译器将 .java 编译为 .class 后,JVM 加载 .class 文件,将类的信息(接口、父类、构造器、方法、变量等)封装到一个 Class 对象中,并存储在方法区;

- **运行时阶段**:通过 Class 对象创建实例,执行对象的方法。

**核心**:类的信息(如成员变量、方法)主要存储在**类对象阶段**的 Class 对象中,反射的所有操作都基于这个 Class 对象。

2.2 Class 对象的获取方式

每个类在 JVM 中都有且仅有一个 Class 对象,获取 Class 对象有三种方式:

(1)通过 Class.forName("全类名") 获取(最常用,支持动态加载)

```java

try {Class clazz = Class.forName("com.qcby.Animal");} catch (ClassNotFoundException e) {e.printStackTrace();}

```

(2)通过 类名.class 获取(编译期确定类,静态方式)

```java

Class clazz = Animal.class;

```

(3)通过 对象.getClass() 获取(基于已有对象)

```java

Animal animal = new Animal();Class clazz = animal.getClass();

```

**验证:三种方式获取的是同一个 Class 对象**

```java

public class Test {public static void main(String[] args) throws ClassNotFoundException {// 方式1Class clazz1 = Class.forName("com.qcby.Animal");// 方式2Class clazz2 = Animal.class;// 方式3Animal animal = new Animal();Class clazz3 = animal.getClass();// 比较是否为同一个对象System.out.println(clazz1 == clazz2); // trueSystem.out.println(clazz2 == clazz3); // true}}

```

**结论**:一个类在一次程序运行过程中只会被加载一次,因此通过任何方式获取的 Class 对象都是同一个。

三、反射实战:获取类的信息

3.1 获取类的成员变量(Field)

通过 Class 对象可以获取类的所有变量(包括公共、私有、静态变量等)。

(1)获取所有声明的变量(含私有、保护):getDeclaredFields()

```java

import java.lang.reflect.Field;import java.util.Arrays;public class FieldDemo {public static void main(String[] args) throws ClassNotFoundException {Class clazz = Class.forName("com.qcby.Animal");Field[] declaredFields = clazz.getDeclaredFields();System.out.println("所有声明的变量:" + Arrays.toString(declaredFields));}}

```

(2)获取公共变量(仅 public 修饰):getFields()

```java

Field[] fields = clazz.getFields();System.out.println("公共变量:" + Arrays.toString(fields));

```

3.2 获取类的方法(Method)

通过 Class 对象可以获取类的所有方法(包括公共、私有、静态方法等)。

(1)获取所有声明的方法(含私有、保护):getDeclaredMethods()

```java

import java.lang.reflect.Method;import java.util.Arrays;public class MethodDemo {public static void main(String[] args) throws ClassNotFoundException {Class clazz = Class.forName("com.qcby.Animal");Method[] declaredMethods = clazz.getDeclaredMethods();System.out.println("所有声明的方法:" + Arrays.toString(declaredMethods));}}

```

(2)获取公共方法(仅 public 修饰,包括继承的方法):getMethods()

```java

Method[] methods = clazz.getMethods();System.out.println("公共方法:" + Arrays.toString(methods));

```

3.3 获取类的构造器(Constructor)

通过 Class 对象可以获取类的所有构造器。

(1)获取所有声明的构造器(含私有、保护):getDeclaredConstructors()

```java

import java.lang.reflect.Constructor;import java.util.Arrays;public class ConstructorDemo {public static void main(String[] args) throws ClassNotFoundException {Class clazz = Class.forName("com.qcby.Animal");Constructor[] declaredConstructors = clazz.getDeclaredConstructors();System.out.println("所有声明的构造器:" + Arrays.toString(declaredConstructors));}}

```

(2)获取公共构造器(仅 public 修饰):getConstructors()

```java

Constructor[] constructors = clazz.getConstructors();System.out.println("公共构造器:" + Arrays.toString(constructors));

```

3.4 获取类的其他信息(父类、接口等)

```java

// 获取父类

Class superClass = clazz.getSuperclass();System.out.println("父类:" + superClass.getName());// 获取实现的接口Class[] interfaces = clazz.getInterfaces();System.out.println("实现的接口:" + Arrays.toString(interfaces));

```

四、反射进阶:动态操作类的成员

4.1 动态创建对象(通过构造器)

```java

import java.lang.reflect.Constructor;public class CreateObjectDemo {public static void main(String[] args) throws Exception {Class clazz = Class.forName("com.qcby.Animal");// 方式1:调用无参构造器(类必须有无参构造器)Animal animal = (Animal) clazz.newInstance(); // JDK 9 后已过时,推荐方式2// 方式2:通过 Constructor 对象调用指定构造器Constructor constructor = clazz.getConstructor(String.class, Integer.class, String.class, String.class);Animal animal2 = (Animal) constructor.newInstance("小花", 2, "雌性", "白色");}}

```

4.2 动态调用方法

```java

import java.lang.reflect.Method;public class InvokeMethodDemo {public static void main(String[] args) throws Exception {Class clazz = Class.forName("com.qcby.Animal");Animal animal = (Animal) clazz.getConstructor().newInstance();// 获取方法:第一个参数是方法名,后面是参数类型Method eatMethod = clazz.getDeclaredMethod("eat", String.class);// 调用方法:第一个参数是对象(静态方法传 null),后面是方法参数eatMethod.invoke(animal, "鱼肉"); // 输出:鱼肉~// 调用静态方法Method staticEatMethod = clazz.getDeclaredMethod("eat", String.class);staticEatMethod.invoke(null, "猫粮"); // 输出:猫粮~}}

```

4.3 动态修改变量

```java

import java.lang.reflect.Field;public class ModifyFieldDemo {public static void main(String[] args) throws Exception {Class clazz = Class.forName("com.qcby.Animal");Animal animal = (Animal) clazz.getConstructor().newInstance();// 获取变量(支持私有变量,需设置可访问)Field nameField = clazz.getDeclaredField("name");nameField.setAccessible(true); // 突破私有访问限制nameField.set(animal, "小黑"); // 修改变量值System.out.println(animal.getName()); // 输出:小黑}}

```

五、反射的优缺点与注意事项

5.1 优点

- **灵活性高**:可在运行时动态操作类,适应框架的可扩展性需求;

- **解耦**:避免硬编码,降低类之间的依赖;

- **元编程支持**:实现“代码生成代码”的高级功能。

5.2 缺点

- **性能开销**:反射操作比直接调用慢(需解析类结构、检查访问权限等);

- **安全性**:可突破访问权限(如修改私有变量),破坏封装性;

- **代码可读性**:反射代码通常比直接调用更晦涩。

5.3 注意事项

- 频繁使用反射的场景(如框架核心逻辑),可通过**缓存 Class、Method、Field 对象**来优化性能;

- 操作私有成员时,需调用 setAccessible(true),但要谨慎使用(避免破坏封装);

- 反射异常(如 ClassNotFoundException、NoSuchMethodException)需显式处理。

六、总结:反射机制核心要点

1. **反射的本质**:运行时获取类信息并动态操作类成员的能力,基于 Class 对象实现;

2. **Class 对象的获取**:Class.forName()、类名.class、对象.getClass(),三者获取的是同一个对象;

3. **反射实战**:可获取类的变量、方法、构造器等信息,也可动态创建对象、调用方法、修改变量;

4. **优缺点**:灵活性高但性能开销大,适合框架开发,普通业务代码需谨慎使用。

反射是 Java 进阶的重要知识点,是理解 Spring、MyBatis 等框架的基础。掌握反射后,你将能更深入地理解 Java 程序的运行机制,也能更灵活地应对复杂的开发场景。

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

相关文章:

  • 如何开发高性能直播美颜sdk?人脸检测、美型算法与渲染优化详解
  • StreamAPI,取出list中的name属性,返回一个新list
  • SSM基于web的佳茗天香茶品销售平台的设计与实现z2m56(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 请别人做网站需要注意什么问题公司做网站怎么做账
  • 茂名网站制作策划如何查看用wordpress建的站点
  • 【湿地数据集4】基于 TOPMODEL模型的1980–2020年全球湿地动态数据集 GWDD
  • C++重点知识梳理(下)
  • 苍穹外卖(第七天)
  • 新乡网站建设制作报价方案网站如何布局
  • 安全狗 网站打不开成都网络营销搜索推广
  • 预测汽车燃油效率——线性回归
  • 【自然语言处理】基于深度学习基的句子边界检测算法
  • 链接脚本(Linker Scripts)
  • 素材网站整站下载WordPress做图床
  • 企业网站相关案例网站建设域名怎么用
  • 太原专业做网站wordpress主体开发
  • 零基础新手小白快速了解掌握服务集群与自动化运维(十八)Ansible自动化模块--安装与入门
  • 【C++11】Lambda表达式+新的类功能
  • C语言编译工具 | 探讨常用C语言编译工具的选择与使用
  • SCT2A26——5.5V-100V Vin,4A峰值电流限制,高效率非同步降压DCDC转换器,兼容替代LM5012
  • 手机网站搜索框代码网上做网站怎么防止被骗
  • 滑动窗口(同向双指针)
  • C语言嵌入式编程实战指南(四):进阶技术和未来展望
  • Mac上的C语言编译软件推荐与使用指南 | 如何选择适合你需求的C语言编译器
  • 做建站较好的网站wordpress edit.php
  • 【大语言模型】-- Function Calling函数调用
  • STM32项目分享:花房环境监测系统
  • 第1章 认识Qt
  • JDK 25 重大兼容性 Bug
  • MyBatis多表联查返回List仅一条数据?主键冲突BUG排查与解决