深入理解Java反射

news2025/4/18 15:57:33

 反射(Reflection)是Java语言的一个强大特性,它允许程序在运行时动态地获取类的信息并操作类或对象的属性、方法和构造器。就是在获取运行时的java字节码文件,通过各种方法去创建对象,反射是Java被视为动态语言的关键特性之一。

反射其实就是获取到内存的class对象,而class对象是类加载器加载了字节码文件转换过来的。

一、反射基础概念

1. 什么是反射

反射是指在程序运行期间,能够动态地获取类的信息(如类名、方法、字段、构造器等)并动态调用对象方法或修改属性的能力。

2. 反射的核心类

Java反射主要涉及以下核心类:

  • Class:表示类的实体

  • Field:表示类的成员变量

  • Method:表示类的方法

  • Constructor:表示类的构造方法

  • Array:提供了动态创建和访问数组的方法

二、反射的基本使用

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

// 1. 通过类名.class
Class<?> clazz1 = String.class;

// 2. 通过对象.getClass()
String str = "Hello";
Class<?> clazz2 = str.getClass();

// 3. 通过Class.forName()
Class<?> clazz3 = Class.forName("java.lang.String");

2. 创建对象

// 使用无参构造器
Class<?> clazz = Class.forName("com.example.User");
User user = (User) clazz.newInstance(); // 已废弃,建议使用getDeclaredConstructor().newInstance()

// 使用有参构造器
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
User user = (User) constructor.newInstance("张三", 25);

3. 获取和操作字段

Class<?> clazz = User.class;
User user = new User("李四", 30);

// 获取public字段
Field nameField = clazz.getField("name"); // 只能获取public字段
nameField.set(user, "王五");

// 获取所有字段(包括private)
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true); // 设置可访问private字段
ageField.set(user, 35);

4. 调用方法 

Class<?> clazz = User.class;
User user = new User();

// 获取public方法
Method publicMethod = clazz.getMethod("publicMethod", String.class);
publicMethod.invoke(user, "参数");

// 获取所有方法(包括private)
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true);
privateMethod.invoke(user);

三、反射的高级特性

1. 动态代理

反射常用于实现动态代理:

interface Subject {
    void request();
}

class RealSubject implements Subject {
    public void request() {
        System.out.println("真实请求");
    }
}

class DynamicProxy implements InvocationHandler {
    private Object target;
    
    public DynamicProxy(Object target) {
        this.target = target;
    }
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理前操作");
        Object result = method.invoke(target, args);
        System.out.println("代理后操作");
        return result;
    }
}

// 使用
Subject realSubject = new RealSubject();
Subject proxy = (Subject) Proxy.newProxyInstance(
    realSubject.getClass().getClassLoader(),
    realSubject.getClass().getInterfaces(),
    new DynamicProxy(realSubject)
);
proxy.request();

2. 注解处理

反射可以用于处理运行时注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyAnnotation {
    String value();
}

class AnnotationProcessor {
    public void process(Object obj) throws Exception {
        for (Method method : obj.getClass().getDeclaredMethods()) {
            if (method.isAnnotationPresent(MyAnnotation.class)) {
                MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
                System.out.println("发现注解方法: " + method.getName() + 
                                 ", 注解值: " + annotation.value());
                method.invoke(obj);
            }
        }
    }
}

3. 泛型类型擦除后的类型获取

虽然Java在运行时擦除了泛型类型信息,但可以通过反射获取字段或方法的泛型签名:

 

class GenericClass<T> {
    private List<String> stringList;
    
    public void setValue(T value) {}
}

// 获取字段的泛型类型
Field field = GenericClass.class.getDeclaredField("stringList");
Type type = field.getGenericType();
if (type instanceof ParameterizedType) {
    ParameterizedType pType = (ParameterizedType) type;
    Type[] actualTypes = pType.getActualTypeArguments(); // [String]
}

// 获取方法的泛型参数类型
Method method = GenericClass.class.getMethod("setValue", Object.class);
Type[] paramTypes = method.getGenericParameterTypes();

四、反射的性能考虑

反射虽然强大,但也有一些缺点:

  1. 性能开销:反射操作比直接调用慢,因为涉及动态类型解析和方法调用验证

  2. 安全限制:反射需要运行时权限,可能被安全管理器限制

  3. 破坏封装:可以访问私有成员,破坏了面向对象的封装性

性能优化建议

  • 缓存Class对象、Method对象等反射结果

  • 对于频繁调用的方法,可以设置setAccessible(true)减少访问检查

  • 考虑使用MethodHandle(Java 7+)作为替代方案

五、反射的应用场景

  1. 框架开发:Spring、Hibernate等框架大量使用反射

  2. 动态代理:AOP编程的基础

  3. IDE开发:如代码提示、自动补全

  4. 测试工具:如JUnit通过反射调用测试方法

  5. 序列化/反序列化:如JSON/XML解析库

  6. 插件系统:动态加载和调用插件

六、反射的替代方案

在Java 7+中,可以使用MethodHandle作为反射的替代方案,它提供了更好的性能:

class MethodHandleDemo {
    public static void main(String[] args) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType type = MethodType.methodType(void.class, String.class);
        MethodHandle handle = lookup.findVirtual(User.class, "publicMethod", type);
        
        User user = new User();
        handle.invokeExact(user, "MethodHandle调用");
    }
}

 

 

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

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

相关文章

Apipost自定义函数深度实战:灵活处理参数值秘籍

在开发过程中&#xff0c;为了更好地处理传递给接口的参数值&#xff0c;解决在调试过程中的数据处理问题&#xff0c;我们经常需要用到函数处理数据。 过去&#xff0c;我们通过预执行脚本来处理数据&#xff0c;先添加脚本&#xff0c;然后将处理后的结果再赋值给请求参数。…

对重大保险风险测试的算法理解

今天与同事聊到重大保险风险测试&#xff0c;借助下面链接的文章&#xff0c; 谈IFRS 17下的重大保险风险测试 - 知乎 谈一下对下图这个公式的理解。 尤其是当看到下面这段文字的解释时&#xff0c;感觉有些算法上的东西&#xff0c;需要再澄清一些。 首先&#xff0c;上面文…

如何白嫖Grok3 API? 如何使用Grok3 API调用实例?怎么使用Grok3模型?

前段时间&#xff0c;Grok3&#xff08;想要体验Grok3的童鞋可以参考本文&#xff1a;Grok 上线角色扮演功能&#xff0c;教你课后作业手到擒来&#xff0c;Grok3使用次数限制&#xff1f;如何使用Grok3? Grok3国内支付手段如何订阅升级Premium - AI is all your need!&#x…

Fast网络速度测试工具

目录 网站简介 功能特点 测试过程 为什么使用Fast 如果网络速度不达标 网站简介 Fast是一个由Netflix提供的网络速度测试工具&#xff0c;主要用来测试用户的互联网下载速度。它以其简洁的界面和快速的测试过程而受到用户的欢迎。 功能特点 下载速度测试&#xff1a;这是…

ubuntu20.04在mid360部署direct_lidar_odometry(DLO)

editor&#xff1a;1034Robotics-yy time&#xff1a;2025.4.10 1.下载DLO&#xff0c;mid360需要的一些...: 1.1 在工作空间/src下 下载DLO&#xff1a; git clone https://github.com/vectr-ucla/direct_lidar_odometry 1.2 在工作空间/src下 下载livox_ros_driver2&…

制造企业数据治理体系搭建与业务赋能实践

当下制造企业正面临着前所未有的机遇与挑战&#xff0c;从多环节业务协同的复杂性&#xff0c;到海量数据资源的沉睡与孤岛化&#xff1b;从个性化定制需求的爆发&#xff0c;到供应链效率优化的迫切性——如何通过数据治理将“数据包袱”转化为“数据资产”&#xff0c;已成为…

【LunarVim】解决which-key 自定义键位注册不成功问题

问题描述 LunarVim将which-key设置放在一个keymaps.lua中&#xff0c;然后config.lua调用reload “user.keymaps”&#xff0c;键位没用注册成功&#xff0c;而直接写在config.lua中&#xff0c;就注册成功 这暴露了LunarVim 插件和配置加载顺序的一些细节坑&#xff0c;下面解…

开源推荐#5:CloudFlare-ImgBed — 基于 CloudFlare Pages 的开源免费文件托管解决方案

大家好&#xff0c;我是 jonssonyan。 寻找一个稳定、快速、还最好是免费或成本极低的图床服务&#xff0c;一直是许多开发者、博主和内容创作者的痛点。公共图床可能说关就关&#xff0c;付费服务又增加成本。现在&#xff0c;一个名为 CloudFlare-ImgBed 的开源项目&#xf…

算法训练之动态规划(三)

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…

xv6-labs-2024 lab2

lab-2 0. 前置 课程记录 操作系统的隔离性&#xff0c;举例说明就是&#xff0c;当我们的shell&#xff0c;或者qq挂掉了&#xff0c;我们不希望因为他&#xff0c;去影响其他的进程&#xff0c;所以在不同的应用程序之间&#xff0c;需要有隔离性&#xff0c;并且&#xff0…

基于FPGA实现BPSK 调制

目录 一、 任务介绍二、基本原理三、基于FPGA实现BPSK 调制四、源码 一、 任务介绍 BPSK 调制在数字通信系统中是一种极重要的调制方式&#xff0c;它的抗干扰噪声性能及通频带的利用率均优先于 ASK 移幅键控和 FSK 移频键控。因此&#xff0c;PSK 技术在中、高速数据传输中得…

在排序数组中查找元素的第一个和最后一个位置 --- 二分查找

目录 一&#xff1a;题目 二&#xff1a;算法原理分析 三&#xff1a;代码实现 一&#xff1a;题目 题目链接&#xff1a; 34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣&#xff08;LeetCode&#xff09; 二&#xff1a;算法原理分析 三&#xff1a;代码实现 c…

631SJBH中小型企业的网络管理模式的方案设计

1.1、研究现状 我国很多企业信息化水平一直还处在非常初级的阶段&#xff0c;有关统计表明&#xff0c;真正实现了计算机较高应用的企业在全国1000多万中小企业中所占的比例还不足10&#xff05;幢3。大多数企业还停留在利用互联网进行网上查询(72&#xff0e;9&#xff05;)、…

LangChain4j(1):初步认识Java 集成 LLM 的技术架构

LangChain 作为构建具备 LLM 能力应用的框架&#xff0c;虽在 Python 领域大放异彩&#xff0c;但 Java 开发者却只能望洋兴叹。LangChain4j 正是为解决这一困境而诞生&#xff0c;它旨在借助 LLM 的强大效能&#xff0c;增强 Java 应用&#xff0c;简化 LLM 功能在Java应用中的…

【C++算法】53.链表_重排链表

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a; 题目链接&#xff1a; 143. 重排链表 题目描述&#xff1a; 解法 模拟 找到链表的中间节点 快慢双指针 把后面的部分逆序 双指针&#xff0c;三指针&#xff0c;头插法 合并两个链表 合并两个有…

多卡分布式训练:torchrun --nproc_per_node=5

多卡分布式训练:torchrun --nproc_per_node=5 1. torchrun 实现规则 torchrun 是 PyTorch 提供的用于启动分布式训练作业的实用工具,它基于 torch.distributed 包,核心目标是简化多进程分布式训练的启动和管理。以下是其主要实现规则: 进程启动 多进程创建:torchrun 会…

Elasticsearch:加快 HNSW 图的合并速度

作者&#xff1a;来自 Elastic Thomas Veasey 及 Mayya Sharipova 过去&#xff0c;我们曾讨论过搜索多个 HNSW 图时所面临的一些挑战&#xff0c;以及我们是如何缓解这些问题的。当时&#xff0c;我们也提到了一些计划中的改进措施。本文正是这项工作的成果汇总。 你可能会问…

图片中文字无法正确显示的解决方案

图片中文字无法正确显示的解决方案 问题描述 在 Linux 系统中生成图片时&#xff0c;图片中的文字&#xff08;如中文&#xff09;未能正确显示&#xff0c;可能表现为乱码或空白。这通常是由于系统缺少对应的字体文件&#xff08;如宋体/SimSun&#xff09;&#xff0c;或者…

ISP--Demosaicking

文章目录 前言算法解释简单的线性插值代码实现 色差法和色比法基于方向加权的方法RB缺失的G通道的插值RB缺失的BR的插值G缺失的BR的插值代码实现 基于边缘检测的方法计算缺失的G计算缺失的RB值/计算缺失的G值 前言 人眼之所以有能感受到自然界的颜色&#xff0c;是因为人眼的感…

国标GB28181协议EasyCVR视频融合平台:5G时代远程监控赋能通信基站安全管理

一、背景介绍 随着移动通信行业的迅速发展&#xff0c;无人值守的通信基站建设规模不断扩大。这些基站大多建于偏远地区&#xff0c;周边人迹罕至、交通不便&#xff0c;给日常的维护带来了极大挑战。其中&#xff0c;位于空旷地带的基站设备&#xff0c;如空调、蓄电池等&…