Java 中的反射是什么?如何使用它?

news2024/9/22 21:15:48

Java 中的反射是什么?如何使用它?

在 Java 编程中,反射是一种高级的编程技术,可以在运行时动态地获取和操作类的信息。反射使得程序可以在运行时对类进行检查和操作,而不需要在编译时知道类的完整信息。这使得程序可以更加灵活和动态地处理对象,同时也为框架和库的开发提供了更大的自由度。

在这里插入图片描述

反射的基本概念

反射的核心是 java.lang.reflect 包中的一些类和接口,它们提供了获取和操作类信息的方法。以下是一些重要的类和接口:

  • Class:表示一个类或接口的类型。
  • Constructor:表示一个类的构造方法。
  • Method:表示一个类的方法。
  • Field:表示一个类的字段。
  • Modifier:表示一个类、方法或字段的修饰符。

反射的基本思路是通过 Class 类来获取类的信息,然后使用其他类和接口来操作这些信息。可以通过以下几种方式获取 Class 对象:

  • 使用 Class.forName() 方法,传入类的全限定名。
  • 使用 .class,例如 String.class
  • 使用对象的 getClass() 方法。

反射的使用

反射的主要用途是在运行时获取和操作类的信息。例如,可以使用反射来动态地创建对象、调用方法和访问字段。以下是一些常见的反射用法:

创建对象

可以使用 Class.newInstance() 方法来创建一个类的实例,例如:

Class<?> clazz = Class.forName("java.util.Date");
Object date = clazz.newInstance();

上面的代码创建了一个 java.util.Date 的实例。由于在编译时无法知道具体的类名,因此使用了 Class.forName() 方法来获取 Class 对象。然后使用 newInstance() 方法创建了一个实例。

调用方法

可以使用 Method 类来调用类的方法,例如:

Class<?> clazz = Class.forName("java.lang.String");
Object str = clazz.newInstance();
Method method = clazz.getMethod("length");
int length = (int) method.invoke(str);

上面的代码创建了一个 java.lang.String 的实例,并调用了它的 length() 方法。首先使用 Class.forName() 方法获取 Class 对象,然后使用 newInstance() 方法创建了一个实例。接下来使用 getMethod() 方法获取 length() 方法对应的 Method 对象,最后使用 invoke() 方法调用了该方法。

访问字段

可以使用 Field 类来访问类的字段,例如:

Class<?> clazz = Class.forName("java.lang.String");
Object str = clazz.newInstance();
Field field = clazz.getDeclaredField("value");
field.setAccessible(true);
char[] value = (char[]) field.get(str);

上面的代码创建了一个 java.lang.String 的实例,并访问了它的 value 字段。首先使用 Class.forName() 方法获取 Class 对象,然后使用 newInstance() 方法创建了一个实例。接下来使用 getDeclaredField() 方法获取 value 字段对应的 Field 对象,然后使用 setAccessible() 方法将访问权限设置为 true,最后使用 get() 方法获取了该字段的值。

获取类信息

可以使用 Class 类来获取类的信息,例如:

Class<?> clazz = Class.forName("java.lang.String");
System.out.println("类名:" + clazz.getName());
System.out.println("包名:" + clazz.getPackage().getName());
System.out.println("父类:" + clazz.getSuperclass().getName());
System.out.println("接口:" + Arrays.toString(clazz.getInterfaces()));

上面的代码获取了 java.lang.String 类的信息,打印了该类的类名、包名、父类和接口。

反射的优缺点

反射的优点在于它可以在运行时动态地获取和操作类的信息,使得程序可以更加灵活和动态地处理对象,同时也为框架和库的开发提供了更大的自由度。反射还可以用于实现类似 Spring 框架中的依赖注入等高级功能。

反射的缺点在于它会带来一定的性能损失,因为访问类的信息需要动态地获取和解析,而不是在编译时就确定好。此外,反射也会降低代码的可读性和可维护性,因为它使得代码更加复杂和难以理解。

示例代码

下面是一个使用反射实现简单的 ORM 框架的示例代码,用于将数据库中的数据映射到 Java 对象中:

public class ORM<T> {
    private final Class<T> clazz;

    public ORM(Class<T> clazz) {
        this.clazz = clazz;
    }

    public List<T> query(String sql) throws Exception {
        List<T> result = new ArrayList<>();
        try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password");
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            while (rs.next()) {
                T obj = clazz.newInstance();
                for (Field field : clazz.getDeclaredFields()) {
                    String name = field.getName();
                    Object value = rs.getObject(name);
                    field.setAccessible(true);
                    field.set(obj, value);
                }
                result.add(obj);
            }
        }
        return result;
    }
}

上面的代码定义了一个 ORM 类,用于将数据库中的数据映射到 Java 对象中。在 query() 方法中,首先使用 JDBC 连接到数据库,并执行查询语句。然后遍历查询结果集,为每条记录创建一个 Java 对象,并将数据库中的字段值赋值给 Java 对象的属性。

可以使用以下代码来测试该 ORM 框架:

public static void main(String[] args) throws Exception {
    ORM<Person> orm = new ORM<>(Person.class);
    List<Person> persons = orm.query("SELECT * FROM person");
    for (Person person : persons) {
        System.out.println(person);
    }
}

public class Person {
    private int id;
    private String name;
    private int age;

    // 省略 getter 和 setter 方法

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

上面的代码定义了一个 Person 类,用于表示人员信息。然后使用上面的 ORM 框架从数据库中查询 person 表中的数据,并将其映射为 Person 对象。

结论

Java 中的反射是一种强大的编程工具,可以在运行时动态地获取和操作类的信息。它可以使程序更加灵活和动态地处理对象,同时也为框架和库的开发提供了更大的自由度。但是,反射也会带来一定的性能损失,并且降低代码的可读性和可维护性。因此,在使用反射时需要权衡其优缺点,并根据具体情况进行选择。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

flstudio怎么保存工程文件?详解FL Studio 21保存文件的方法

FL Studio 21全称Fruity Loops Studio2023&#xff0c;这款软件也被人们亲切的称之为水果&#xff0c;它是一款功能强大的音乐创作编辑软件&#xff0c;拥有全功能的录音室&#xff0c;大混音盘以及先进的音乐制作工具&#xff0c;用户通过使用该软件&#xff0c;就可以轻松制作…

Ubuntu下搭建Redis分片集群

目录 准备实例和配置 启动分片集群 测试分片集群 分片集群需要的节点数量较多&#xff0c;搭建一个最小的分片集群&#xff0c;包含3个master节点&#xff0c;每个master包含一个slave节点&#xff0c;并且master之间通过心跳机制互相监听&#xff0c;此模式下不需要哨兵监听…

js高级进阶:promise同步编程技巧

promise是ES6引进的异步编程解决方案&#xff0c;是一个构造函数&#xff0c;可以实例化对象&#xff0c;可以解决回调地狱的问题。 首先我们看一下promise的实例化对象是什么&#xff1a; let P new Promise(function(){});//new一个promise传入一个函数console.log(P);打印结…

读发布!设计与部署稳定的分布式系统(第2版)笔记23_互联层之DNS

1. 互连层是可以真正构建高可用性的地方 1.1. 流量管理 1.2. 负载均衡 1.3. 服务发现 2. 不同规模的解决方案 2.1. 在小公司中 2.1.1. 只有少数开发人员的小企业可以直接使用DNS条目 2.1.2. 生成变更的开发人员较少&#xff0c;变更频度变低 2.1.3. 可能根本就没有独立…

高阶C语言|指针的进阶

指针的主题&#xff0c;在指针初阶阶段&#xff0c;我们知道了指针的概念&#xff1a; 1.指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间。 2.指针的大小是固定4/8个字节&#xff08;32为平台/64位平台&#xff09;。 3.指针是有类型&#xff0c…

java+springboot基于云的学习笔记系统设计与开发 _44va6

学习笔记系统按照权限的类型进行划分&#xff0c;分为管理员和用户共两个模块。系统实现登录、个人信息修改&#xff0c;还可以对个人中心&#xff0c;用户管理&#xff0c;笔记本管理&#xff0c;笔记分享管理&#xff0c;分享类型管理&#xff0c;学习资料管理&#xff0c;购…

Makefile:10分钟带你了解makefile

1、Makefile是什么 在Linux系统中&#xff0c;Makefile是一个脚本文件&#xff0c;通常名为Makefile或者makefile&#xff0c;它使得程序员能够快速便捷地完成调用程序、编译代码、定位故障等工作。 Makefile是一个用于自动化构建和编译程序的脚本文件。它包含了程序的所有源…

Ubuntu下配置Redis哨兵集群

目录 准备实例和配置 启动哨兵集群 测试配置 搭建一个三节点形成的Sentinel集群&#xff0c;来监管Redis主从集群。 三个sentinel哨兵实例信息如下&#xff1a; 节点IPPORTs1192.168.22.13527001s2192.168.22.13527002s3192.168.22.13527003 准备实例和配置 要在同一台虚…

01. Docker基础环境构建

目录 1、前言 2、关于Docker 2.1、几个术语 2.2、Docker容器化的价值 3、搭建基础环境 3.1、安装VMware 3.2、安装Doker 3.3、启动 3.4、验证Docker环境 4、小结 1、前言 在这里我们将学习关于Docker的一些技能知识&#xff0c;那么首先我们应该怼Docker有一个基础的…

服务器离线部署docker,镜像迁移,mysql主从搭建等服务

公司项目要上线项目&#xff0c;买了两台云服务器&#xff0c;需进行环境部署&#xff08;1台接入公网&#xff0c;一台只能局域网访问&#xff09;&#xff0c;主要部署以下内容 1、服务器之间配置ssh免密 2、离线docker部署 3、docker镜像迁移 4、redis服务 5、minio文件…

Idea配置Maven优先从本地仓库获取依赖

idea配置maven依赖优先从指定本地仓库获取 在设置中搜索 Runner ,在VM Option中设置参数-DarchetypeCataloginternal <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http…

沐风老师MaxScript快速入门教程

Maxscript是将自定义3dMax应用的更强大的方法之一。结合内置的侦听器和编辑器&#xff0c;我们在运行时操作和测试代码&#xff0c;使其成为用户试验和探索改进软件体验的强大选项。通过Maxscript&#xff0c;我们几乎可以操作软件中的每一个对象&#xff0c;包括但不限于&…

【C++】-vector的模拟实现(以及memcpy如何使用)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

Spring-MVC的注解扫描-spring17

包括我们业务层和Dao层&#xff0c;去帮助别人去扫 只扫controller下的注解

00_YS_硬件电路图

1.主控制芯片的型号 STM32F407IGT6&#xff0c;LQFP-176&#xff0c;1MB 内部 FLASH&#xff0c;192KB RAM USART3 RS485 通信&#xff0c;芯片使用 SP3072EEN; UART5 RS232 通信&#xff0c; CAN 1 路&#xff0c;型号 SN65HVD230 USB 支持 …

Python应用实例(二)数据可视化(三)

数据可视化&#xff08;三&#xff09; 1.使用Plotly模拟掷骰子1.1 安装Plotly1.2 创建Die类1.3 掷骰子1.4 分析结果1.5 绘制直方图1.6 同时掷两个骰子1.7 同时掷两个面数不同的骰子 1.使用Plotly模拟掷骰子 本节将使用Python包Plotly来生成交互式图表。需要创建在浏览器中显示…

代码随想录算法训练营第十九天 | 动态规划系列5,6,7,8

动态规划系列5,6,7,8 377 组合总和 Ⅳ未看解答自己编写的青春版重点代码随想录的代码我的代码(当天晚上理解后自己编写) 爬楼梯进阶322 零钱兑换未看解答自己编写的青春版写完这道题后的感受重点代码随想录的代码动态规划&#xff0c;也要时刻想着剪枝操作。我的代码(当天晚上理…

异常执行结果随笔

前段时间有朋友问我异常执行顺序问题&#xff0c;这里简单记录下哈。 伪代码描述&#xff0c;当j0和j1&#xff0c;输出结果分别是什么&#xff1f; int i 0; int j 0或1; try {j i / j&#xff1b;System.out.println(i);return i; } catch (Exception e) {System.out.pri…

win10如何使用wsl配置Ubuntu并使用vscode连接

文章目录 0. 前置资料1. 下载wsl2. 下载Ubuntu3. vscode连接wsl 0. 前置资料 wsl为适用于 Linux 的 Windows 子系统&#xff0c;可参考以下微软的官方文档 https://learn.microsoft.com/zh-cn/windows/wsl/ 1. 下载wsl 点击屏幕左下角的放大镜&#xff0c;直接在输入框键入P…

第 354 场LeetCode周赛

A 特殊元素平方和 模拟 class Solution { public:int sumOfSquares(vector<int> &nums) {int res 0;int n nums.size();for (int i 0; i < n; i)if (n % (i 1) 0)res nums[i] * nums[i];return res;} };B 数组的最大美丽值 差分数组: n u m s [ i ] nums[…