Java 反射(Reflection)

Java 反射(Reflection)

Java 反射(Reflection)是一个强大的特性,它允许程序在运行时查询、访问和修改类、接口、字段和方法的信息。反射提供了一种动态地操作类的能力,这在很多框架和库中被广泛使用,例如Spring框架的依赖注入。

反射 API

Java 的反射 API 提供了一系列的类和接口来操作 Class 对象。主要的类包括:

  • java.lang.Class:表示类的对象。提供了方法来获取类的字段、方法、构造函数等。
  • java.lang.reflect.Field:表示类的字段(属性)。提供了访问和修改字段的能力。
  • java.lang.reflect.Method:表示类的方法。提供了调用方法的能力。
  • java.lang.reflect.Constructor:表示类的构造函数。提供了创建对象的能力。

工作流程

  1. 获取 Class 对象:首先获取目标类的 Class 对象。
  2. 获取成员信息:通过 Class 对象,可以获取类的字段、方法、构造函数等信息。
  3. 操作成员:通过反射 API 可以读取和修改字段的值、调用方法以及创建对象。

以下是 Java 反射的基本使用方式及其常见应用。

1. 获取 Class 对象

每个类在 JVM 中都有一个与之相关的 Class 对象。可以通过以下方式获取 Class 对象:

通过类字面量

Class<?> clazz = String.class;

通过对象实例:

String str = "Hello";
Class<?> clazz = str.getClass();

通过 Class.forName() 方法:

Class<?> clazz = Class.forName("java.lang.String");

2. 创建对象

可以使用反射动态创建对象:

Class<?> clazz = Class.forName("java.lang.String");
Object obj = clazz.getDeclaredConstructor().newInstance();

3. 访问字段

可以通过反射访问和修改类的字段:

Class<?> clazz = Person.class;
Field field = clazz.getDeclaredField("name");
field.setAccessible(true); // 如果字段是私有的,需要设置为可访问
Object value = field.get(personInstance); // 获取字段值
field.set(personInstance, "New Name"); // 设置字段值

4. 调用方法

可以通过反射调用类的方法:

Class<?> clazz = Person.class;
Method method = clazz.getMethod("sayHello");
method.invoke(personInstance);

Method methodWithArgs = clazz.getMethod("greet", String.class);
methodWithArgs.invoke(personInstance, "World");

5. 获取构造函数

可以使用反射获取和调用构造函数:

Class<?> clazz = Person.class;
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("John", 30);

6. 获取接口和父类

可以使用反射获取类实现的接口和父类:

Class<?> clazz = Person.class;

// 获取所有接口
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> i : interfaces) {
    System.out.println("Interface: " + i.getName());
}

// 获取父类
Class<?> superClass = clazz.getSuperclass();
System.out.println("Superclass: " + superClass.getName());

以下是一个完整的示例,展示了如何使用反射来创建对象、访问字段和调用方法:

实例

**import** java.lang.reflect.Constructor;
**import** java.lang.reflect.Field;
**import** java.lang.reflect.Method;

**public** **class** ReflectionExample {

  **public** **static** **void** main(String[] args) **throws** Exception {
    *// 获取 Class 对象*
    Class<?> clazz = Person.**class**;
    
    *// 创建对象*
    Constructor<?> constructor = clazz.getConstructor(String.**class**, **int**.**class**);
    Object person = constructor.newInstance("John", 30);
    
    *// 访问字段*
    Field nameField = clazz.getDeclaredField("name");
    nameField.setAccessible(**true**);
    System.out.println("Name: " + nameField.get(person));
    
    *// 修改字段*
    nameField.set(person, "Doe");
    System.out.println("Updated Name: " + nameField.get(person));
    
    *// 调用方法*
    Method greetMethod = clazz.getMethod("greet", String.**class**);
    greetMethod.invoke(person, "World");
  }
}

**class** Person {
  **private** String name;
  **private** **int** age;

  **public** Person(String name, **int** age) {
    **this**.name = name;
    **this**.age = age;
  }

  **public** **void** greet(String message) {
    System.out.println(name + " says: " + message);
  }
}

编译执行以上代码,输出结果为:

Name: John
Updated Name: Doe
Doe says: World

java.lang.reflect

java.lang.reflect 是 Java 反射机制的核心包,提供了操作类及其成员(字段、方法、构造函数等)的类和接口。通过这些 API,开发者可以在运行时动态地查询和修改类的结构。

img

以下是 java.lang.reflect 包中的主要类和接口的详细介绍:

1. Class

  • 功能:表示类的对象,提供了获取类信息的方法,如字段、方法、构造函数等。

  • 主要方法

    • getFields():获取所有公共字段。
    • getDeclaredFields():获取所有声明的字段,包括私有字段。
    • getMethods():获取所有公共方法。
    • getDeclaredMethods():获取所有声明的方法,包括私有方法。
    • getConstructors():获取所有公共构造函数。
    • getDeclaredConstructors():获取所有声明的构造函数,包括私有构造函数。
    • getSuperclass():获取类的父类。
    • getInterfaces():获取类实现的所有接口。

2. Field

  • 功能:表示类的字段(属性),提供了访问和修改字段值的方法。

  • 主要方法

    • get(Object obj):获取指定对象的字段值。
    • set(Object obj, Object value):设置指定对象的字段值。
    • getType():获取字段的数据类型。
    • getModifiers():获取字段的修饰符(如 public、private)。

3. Method

  • 功能:表示类的方法,提供了调用方法的能力。

  • 主要方法

    • invoke(Object obj, Object... args):调用指定对象的方法。
    • getReturnType():获取方法的返回类型。
    • getParameterTypes():获取方法的参数类型。
    • getModifiers():获取方法的修饰符(如 public、private)。

4. Constructor

  • 功能:表示类的构造函数,提供了创建对象的能力。

  • 主要方法

    • newInstance(Object... initargs):创建一个新实例,使用指定的构造函数参数。
    • getParameterTypes():获取构造函数的参数类型。
    • getModifiers():获取构造函数的修饰符(如 public、private)。

示例代码

以下是使用 java.lang.reflect 包进行反射操作的示例:

实例

**import** java.lang.reflect.Field;
**import** java.lang.reflect.Method;
**import** java.lang.reflect.Constructor;

**public** **class** ReflectionExample {

  **public** **static** **void** main(String[] args) **throws** Exception {
    *// 获取 Class 对象*
    Class<?> clazz = Car.**class**;*// 创建 Car 对象*Constructor<?> constructor = clazz.getConstructor(String.**class**, **int**.**class**);Object car = constructor.newInstance("Toyota", 2020);*// 访问和修改字段*Field modelField = clazz.getDeclaredField("model");Field yearField = clazz.getDeclaredField("year");
​    
​    *// 设置字段为可访问(如果字段是私有的)*
​    modelField.setAccessible(**true**);
​    yearField.setAccessible(**true**);
​    
​    *// 打印原始字段值*System.out.println("Original Model: " + modelField.get(car));System.out.println("Original Year: " + yearField.get(car));
​    
​    *// 修改字段值*
​    modelField.set(car, "Honda");
​    yearField.set(car, 2024);
​    
​    *// 打印修改后的字段值*System.out.println("Updated Model: " + modelField.get(car));System.out.println("Updated Year: " + yearField.get(car));
​    
​    *// 调用方法*Method startMethod = clazz.getMethod("start");
​    startMethod.invoke(car);
  }
}

**class** Car {
  **private** String model;
  **private** **int** year;

  **public** Car(String model, **int** year) {
    **this**.model = model;
    **this**.year = year;
  }

  **public** **void** start() {
    System.out.println("The " + model + " car of year " + year + " is starting.");
  }
}

编译执行以上代码,输出结果为:

Original Model: Toyota
Original Year: 2020
Updated Model: Honda
Updated Year: 2024
The Honda car of year 2024 is starting.
r;
  }

  **public** **void** start() {
    System.out.println("The " + model + " car of year " + year + " is starting.");
  }
}

编译执行以上代码,输出结果为:

Original Model: Toyota
Original Year: 2020
Updated Model: Honda
Updated Year: 2024
The Honda car of year 2024 is starting.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/924722.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入浅出剖析典型文生图产品Midjourney

2022年7月,一个小团队推出了公测的 Midjourney,打破了 AIGC 领域的大厂垄断。作为一个精调生成模型,以聊天机器人方式部署在 Discord,它创作的《太空歌剧院》作品,甚至获得了美国「数字艺术/数码摄影」竞赛单元一等奖。 这一事件展示了 AI 在绘画领域惊人的创造力,让人们…

【Linux】磁盘 | 文件系统 | inode

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;青果大战linux 总有光环在陨落&#xff0c;总有新星在闪烁 模电好难啊&#xff…

PHP 去掉特殊不可见字符 “\u200e“

描述 最近在排查网站业务时&#xff0c;发现有数据匹配失败的情况 肉眼上完全看不出问题所在 当把字符串 【M24308/23-14F‎】复制出来发现 末尾有个不可见的字符 使用删除键或左右移动时才会发现 最后测试通过 var_dump 打印 发现这个"空字符"占了三个长度 &#xf…

【C#设计模式(15)——命令模式(Command Pattern)】

前言 命令模式的关键通过将请求封装成一个对象&#xff0c;使命令的发送者和接收者解耦。这种方式能更方便地添加新的命令&#xff0c;如执行命令的排队、延迟、撤销和重做等操作。 代码 #region 基础的命令模式 //命令&#xff08;抽象类&#xff09; public abstract class …

使用zabbix监控k8s

一、 参考文献 小阿轩yx-案例&#xff1a;Zabbix监控kubernetes云原生环境 手把手教你实现zabbix对Kubernetes的监控 二、部署经验 关于zabbix监控k8s&#xff0c;总体来说是分为两块内容&#xff0c;一是在k8s集群部署zabbix-agent和zabbix- proxy。二是在zabbix进行配置。…

ThingsBoard规则链节点:GCP Pub/Sub 节点详解

目录 引言 1. GCP Pub/Sub 节点简介 2. 节点配置 2.1 基本配置示例 3. 使用场景 3.1 数据传输 3.2 数据分析 3.3 事件通知 3.4 任务调度 4. 实际项目中的应用 4.1 项目背景 4.2 项目需求 4.3 实现步骤 5. 总结 引言 ThingsBoard 是一个开源的物联网平台&#xff0…

10.机器学习--集成学习

机器学习领域有一个强大的思路&#xff1a;集成学习&#xff0c;该方法在诸多机器学习竞赛中往往能够获得最优的结果。集成学习的基本思想实际上非常简单&#xff1a;三个臭皮匠顶一个诸葛亮&#xff0c;即将多个模型组合在一起获得的效果往往要强于单一模型。 目录 集成学习…

结构体详解+代码展示

系列文章目录 &#x1f388; &#x1f388; 我的CSDN主页:OTWOL的主页&#xff0c;欢迎&#xff01;&#xff01;&#xff01;&#x1f44b;&#x1f3fc;&#x1f44b;&#x1f3fc; &#x1f389;&#x1f389;我的C语言初阶合集&#xff1a;C语言初阶合集&#xff0c;希望能…

深度解析猎板 PCB树脂塞孔工艺

PCB 的树脂塞孔工艺是一种在印制电路板制造过程中广泛应用的重要技术&#xff0c;以下是猎板PCB批量工厂对PCB树脂塞孔该工艺的详细介绍&#xff1a; 猎板 PCB树脂塞孔工艺目的 防止短路&#xff1a;在 PCB 制造中&#xff0c;若过孔未被有效封堵&#xff0c;锡膏可能会从孔内…

扫雷-完整源码(C语言实现)

云边有个稻草人-CSDN博客 在学完C语言函数之后&#xff0c;我们就有能力去实现简易版扫雷游戏了&#xff08;成就感满满&#xff09;&#xff0c;下面是扫雷游戏的源码&#xff0c;快试一试效果如何吧&#xff01; 在test.c里面进行扫雷游戏的测试&#xff0c;game.h和game.c…

当前就业形势下C++方向后端开发学习指南

文章目录 1. C后端开发的职业方向1.1 C的应用领域1.2 后端开发的职业选择 2. 当前就业形势分析2.1 C开发者的市场需求2.2 C开发者的薪资水平 3. 学习路线3.1 入门阶段&#xff1a;掌握基础知识3.2 进阶阶段&#xff1a;掌握后端开发的核心技术3.2.1 数据库与C3.2.2 网络编程 3.…

FFmpeg 简介与编译

1. ffmpeg 简介&#xff1a; FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec&#xff0c;为了保证高可移…

【论文复现】BERT论文解读及情感分类实战

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ BERT论文解读及情感分类实战 简介BERT文章主要贡献BERT模型架构技术细节任务1 Masked LM&#xff08;MLM&#xff09;任务2 Next Sentence P…

Flink高可用配置(HA)

从Flink架构中我们可以看到,JobManager这个组件非常重要,是中心协调器,负责任务调度和资源管理。默认情况下,每个Flink集群只有一个JobManager实例。这会产生单点故障(SPOF):如果JobManager崩溃,则无法提交新程序,正在运行的程序也会失败。通过JobManager的高可用性,…

【Rabbitmq篇】高级特性----事务,消息分发

目录 事务 消息分发 应用场景 1. 限流 2.负载均衡 事务 RabbitMQ是基于AMQP协议实现的,该协议实现了事务机制,因此RabbitMQ也支持事务机制.SpringAMQP也提供了对事务相关的操作.RabbitMQ事务允许开发者确保消息的发送和接收是原子性的,要么全部成功,要么全部失败. 何为原…

优先算法 —— 双指针系列 - 有效三角形的个数

1. 有效三角形的个数 题目链接&#xff1a; 611. 有效三角形的个数 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/valid-triangle-number/description/ 2. 题目解析 以示例1为例&#xff1a; 3. 优化 我们都知道&#xff0c;判断三角形的方法就是两边相…

【H2O2|全栈】Node.js(2)

目录 前言 开篇语 准备工作 npm 概念 常见指令 项目中的包 创建项目 启动项目 服务器搭建 express 基本步骤 搭建应用 创建路由 监听端口 启动服务器 面试相关 结束语 前言 开篇语 本系列博客分享Node.js的相关知识点&#xff0c;本章讲解npm与服务器的简单…

Android 13 Aosp 默认允许应用动态权限

图库 frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java 修改 public void grantDefaultPermissions(int userId) {DelayingPackageManagerCache pm new DelayingPackageManagerCache();grantPermissionsToSysCompon…

【NLP高频面题 - LLM架构篇】LLM对Transformer都有哪些优化?

【NLP高频面题 - LLM架构篇】LLM对Transformer都有哪些优化&#xff1f; ⚠︎ 重要性&#xff1a;★★★ &#x1f4af; NLP Github 项目&#xff1a; NLP 项目实践&#xff1a;fasterai/nlp-project-practice 介绍&#xff1a;该仓库围绕着 NLP 任务模型的设计、训练、优化、…

DAY139权限提升-Linux系统权限提升篇Vulnhub辅助项目SUID权限SUDO指令版本漏洞

Linux提权 1、内核溢出提权 2、suid、sudo、nfs、path、ld_preload、cron、lxd、capability、rbash等 3、数据库类型提权 Linux&#xff1a; 系统用户&#xff1a;UID(0-999) 普通用户&#xff1a;UID(1000-*) root用户&#xff1a;UID为0&#xff0c;拥有系统的完全控制…