深入浅出Java反射:掌握动态编程的艺术

  • 小程一言
  • 反射
    • 何为反射
    • 反射核心类
    • 反射的基本使用
      • 获取`Class`对象
      • 创建对象
      • 调用方法
      • 访问字段
    • 示例程序
    • 应用场景
    • 优缺点分析
      • 优点
      • 缺点
    • 注意
  • 再深入一些
    • 反射与泛型
    • 反射与注解
    • 反射与动态代理
    • 反射与类加载器
  • 结语

小程一言

本专栏是对Java知识点的总结。在学习Java的过程中,学习的笔记,加入自己的思考,结合各种资料的整理。

文章与程序一样,一定都是不完美的,因为不完美,才拥有不断追求完美的动力

以下是符合您要求的博客文章,主类名为crj,内容全面细致,深度适中,字数约5000字。

---

反射

Java反射是Java语言中一项强大的功能,它允许程序在运行时动态地获取类的信息并操作类的属性、方法和构造方法。反射机制为Java提供了极大的灵活性,广泛应用于框架开发、动态代理、注解处理等场景。本文将详细介绍Java反射的核心概念、使用方法以及注意事项,并通过示例代码帮助读者更好地理解。


何为反射

简单来说,反射是指在程序运行时,能够动态地获取类的信息(如类名、方法、字段、构造方法等),并能够操作这些信息。通过反射,我们可以在运行时创建对象、调用方法、访问字段,甚至修改私有成员的值。

反射的核心类是java.lang.reflect包中的ClassMethodFieldConstructor。通过这些类,我们可以实现动态编程。

在这里插入图片描述

反射核心类

  1. Class<T>: 表示一个类或接口的类型信息。通过Class对象可以获取类的构造方法、方法和字段。
  2. Constructor<T>: 表示类的构造方法,用于创建对象。
  3. Method: 表示类的方法,用于调用方法。
  4. Field: 表示类的字段,用于访问或修改字段的值。

反射的基本使用

获取Class对象

要使用反射,首先需要获取目标类的Class对象。以下是三种常见的获取方式:

  • Class.forName("全限定类名"): 通过类的全限定名获取Class对象。
  • 对象.getClass(): 通过对象实例获取Class对象。
  • 类名.class: 直接通过类名获取Class对象。
// 示例:获取String类的Class对象
Class<?> clazz = Class.forName("java.lang.String");

创建对象

通过Class对象可以获取类的构造方法,并调用newInstance()方法创建对象。

// 示例:通过反射创建String对象
Class<?> clazz = Class.forName("java.lang.String");
Constructor<?> constructor = clazz.getConstructor(); // 获取无参构造方法
Object obj = constructor.newInstance(); // 创建对象
System.out.println("创建的对象: " + obj);

调用方法

通过Class对象可以获取类的方法,并调用invoke()方法执行方法。

// 示例:通过反射调用String的length()方法
Class<?> clazz = Class.forName("java.lang.String");
Method method = clazz.getMethod("length"); // 获取length()方法
int length = (int) method.invoke("Hello"); // 调用方法
System.out.println("字符串长度: " + length);

访问字段

通过Class对象可以获取类的字段,并访问或修改字段的值。

// 示例:通过反射访问Integer的value字段
Class<?> clazz = Class.forName("java.lang.Integer");
Field field = clazz.getDeclaredField("value"); // 获取value字段
field.setAccessible(true); // 设置可访问私有字段
int value = (int) field.get(10); // 获取字段值
System.out.println("字段值: " + value);

在这里插入图片描述

示例程序

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

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

public class crj {

    public static void main(String[] args) {
        try {
            // 1. 获取Class对象
            Class<?> clazz = Class.forName("java.lang.String");

            // 2. 创建对象
            Constructor<?> constructor = clazz.getConstructor();
            Object obj = constructor.newInstance();
            System.out.println("创建的对象: " + obj);

            // 3. 调用方法
            Method method = clazz.getMethod("length");
            int length = (int) method.invoke("Hello");
            System.out.println("字符串长度: " + length);

            // 4. 访问字段
            Class<?> integerClass = Class.forName("java.lang.Integer");
            Field field = integerClass.getDeclaredField("value");
            field.setAccessible(true);
            int value = (int) field.get(10);
            System.out.println("Integer的value字段值: " + value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

应用场景

  1. 动态代理: 在运行时创建代理对象,例如Spring AOP。
  2. 框架开发: 如Spring通过反射管理Bean的生命周期。
  3. 注解处理: 在运行时读取注解信息,例如JUnit的测试框架。
  4. 工具开发: 如IDE的代码提示功能。

优缺点分析

优点

  • 灵活性高: 可以在运行时动态操作类和方法。
  • 功能强大: 适用于框架和工具开发。

缺点

  • 性能较低: 反射操作比直接调用慢。
  • 破坏封装性: 可以访问私有成员,可能导致安全问题。
  • 代码可读性差: 反射代码通常难以理解和维护。

注意

  1. 性能问题: 反射操作较慢,频繁使用时需谨慎。
  2. 安全性: 反射可以绕过访问控制,需确保代码的安全性。
  3. 异常处理: 反射操作可能抛出IllegalAccessExceptionInvocationTargetException等异常,需妥善处理。

在这里插入图片描述

再深入一些

将能联系到的地方都牵连一下,希望能给你更多的思考

反射与泛型

Java反射机制在处理泛型时需要注意类型擦除的问题。由于Java的泛型是通过类型擦除实现的,因此在运行时无法直接获取泛型的具体类型信息。但是,可以通过ParameterizedType等接口来获取泛型的信息。

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class crj{

    public static class GenericClass<T> {
        public void printType() {
            Type type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
            System.out.println("泛型类型: " + type);
        }
    }

    public static void main(String[] args) {
        GenericClass<String> genericClass = new GenericClass<String>() {};
        genericClass.printType();
    }
}

反射与注解

Java反射机制可以用于读取和处理注解。通过反射,我们可以在运行时获取类、方法、字段上的注解信息,并根据注解的值执行相应的逻辑。

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

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

public class AnnotationReflectionExample {

    @MyAnnotation("Hello, Annotation!")
    public void annotatedMethod() {
        System.out.println("这是一个带有注解的方法");
    }

    public static void main(String[] args) throws Exception {
        Method method = AnnotationReflectionExample.class.getMethod("annotatedMethod");
        MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
        System.out.println("注解值: " + annotation.value());
    }
}

在这里插入图片描述

反射与动态代理

Java反射机制在动态代理中扮演着重要角色。通过Proxy类和InvocationHandler接口,我们可以在运行时创建代理对象,并在调用方法时执行额外的逻辑。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface MyInterface {
    void doSomething();
}

public class DynamicProxyExample {

    public static void main(String[] args) {
        MyInterface realObject = new MyInterface() {
            @Override
            public void doSomething() {
                System.out.println("真实对象的方法");
            }
        };

        MyInterface proxyObject = (MyInterface) Proxy.newProxyInstance(
                MyInterface.class.getClassLoader(),
                new Class<?>[] { MyInterface.class },
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("方法调用前");
                        Object result = method.invoke(realObject, args);
                        System.out.println("方法调用后");
                        return result;
                    }
                }
        );

        proxyObject.doSomething();
    }
}

反射与类加载器

Java反射机制与类加载器密切相关。通过自定义类加载器,我们可以在运行时动态加载类,并使用反射机制操作这些类。

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;

public class CustomClassLoader extends ClassLoader {

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData = loadClassData(name);
        return defineClass(name, classData, 0, classData.length);
    }

    private byte[] loadClassData(String className) {
        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(className.replace('.', '/') + ".class");
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        int bufferSize = 4096;
        byte[] buffer = new byte[bufferSize];
        int bytesRead;
        try {
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return byteArrayOutputStream.toByteArray();
    }

    public static void main(String[] args) throws Exception {
        CustomClassLoader customClassLoader = new CustomClassLoader();
        Class<?> clazz = customClassLoader.loadClass("com.example.MyClass");
        Object obj = clazz.getDeclaredConstructor().newInstance();
        Method method = clazz.getMethod("myMethod");
        method.invoke(obj);
    }
}

在这里插入图片描述

结语

Java反射是一项强大的功能,它为Java提供了动态编程的能力。通过反射,我们可以在运行时获取类的信息并操作类的成员。尽管反射具有很高的灵活性,但也存在性能和安全性的问题。在实际开发中,应根据需求合理使用反射,避免滥用。

希望本文能帮助你更好地理解Java反射机制!如果你有任何问题或建议,欢迎在评论区留言。

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

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

相关文章

QGIS如何查看海拔剖面图

一、基础概念与工具准备 地形剖面图定义 地形剖面图是沿地表某一直线方向的垂直断面图&#xff0c;用于展示地势起伏、坡度变化和海拔分布。其核心要素包括水平距离轴&#xff08;X轴&#xff09;和海拔高度轴&#xff08;Y轴&#xff09;&#xff0c;可通过等高线或数字高程模…

vnctf2025--学生姓名登记系统

首先进入靶场 先随便输入一个123试试 这个地方将123直接回显出来&#xff0c;很有可能是ssti模板注入&#xff0c;输入{{7*7}}看看是否回显 回显49&#xff0c;说明确实有这个漏洞 现在知道是ssti模板注入了&#xff0c;下一步应该是确定模板引擎是什么 这个时候需要看题目给…

清华大学新闻与传播学院沈阳团队出品的《DeepSeek:从入门到精通》104页PDF

前言 本机运行DeepSeek R1大模型文章如下&#xff1a; Windows电脑本地部署运行DeepSeek R1大模型&#xff08;基于Ollama和Chatbox&#xff09;【保姆级万字教程】在Windows计算机部署DeepSeek大模型&#xff0c;给在实验室无外网的同事们用&#xff08;基于Ollama和OpenWebUI…

Jenkins 通过 Execute Shell 执行 shell 脚本 七

Jenkins 通过 Execute Shell 执行 shell 脚本 七 一、创建 .sh 文件 项目目录下新建 .sh 文件 jenkins-script\shell\ci_android_master.sh添加 Execute Shell 模块 在 Command 中添加 # 获取 .sh 路径 CI_ANDROID_MASTER_PATH"${WORKSPACE}/jenkins-script/shell/…

开发完的小程序如何分包

好几次了&#xff0c;终于想起来写个笔记记一下 我最开始并不会给小程序分包&#xff0c;然后我就各种搜&#xff0c;发现讲的基本上都是开发之前的小程序分包&#xff0c;可是我都开发完要发布了&#xff0c;提示我说主包太大需要分包&#xff0c;所以我就不会了。。。 好了…

bitcoinjs学习1—P2PKH

1. 概述 在本学习笔记中&#xff0c;我们将深入探讨如何使用 bitcoinjs-lib 库构建和签名一个 P2PKH&#xff08;Pay-to-PubKey-Hash&#xff09; 比特币交易。P2PKH 是比特币网络中最常见和最基本的交易类型之一&#xff0c;理解其工作原理是掌握比特币交易构建的关键。 想要详…

有限状态系统的抽象定义及CEGAR分析解析理论篇

文章目录 一、有限状态系统的抽象定义及相关阐述1、有限状态系统定义2、 有限状态系统间的抽象关系&#xff08;Abstract&#xff09;2.1 基于函数的抽象定义2.2 基于等价关系的抽象定义 二、 基于上面的定义出发&#xff0c;提出的思考1. 为什么我们想要/需要进行抽象2. 抽象是…

【linux学习指南】线程同步与互斥

文章目录 &#x1f4dd;线程互斥&#x1f320; 库函数strncpy&#x1f309;进程线程间的互斥相关背景概念&#x1f309;互斥量mutex &#x1f320;线程同步&#x1f309;条件变量&#x1f309;同步概念与竞态条件&#x1f309; 条件变量函数 &#x1f6a9;总结 &#x1f4dd;线…

云上话ai

这两天参加了几场ai视频直播 今天想分享一下照片&#xff0c;记录一下&#xff5e;

OpenVINO 2025.0重磅升级:开启⽣成式AI全场景⾰命!

2025年2⽉6⽇&#xff0c;英特尔OpenVINO™ 2025.0版本震撼发布&#xff0c;本次升级堪称近三年最⼤规模技术⾰新&#xff01;从⽣成 式AI性能跃升到全栈硬件⽀持&#xff0c;从开发者⼯具链优化到边缘计算突破&#xff0c;六⼤核⼼升级重新定义AI部署效率。 一&#xff0c;&a…

语言大模型基础概念 一(先了解听说过的名词都是什么)

SFT&#xff08;监督微调&#xff09;和RLHF&#xff08;基于人类反馈的强化学习&#xff09;的区别 STF&#xff08;Supervised Fine-Tuning&#xff09;和RLHF&#xff08;Reinforcement Learning from Human Feedback&#xff09;是两种不同的模型训练方法&#xff0c;分别…

裙子贴图提示词【图生图】

正向&#xff1a; (a plaid short skirt with checkered texture:1.4),(no human figure),wallpaper,incredibly absurdres,huge filesize,highres,absurdres,artbook_game c,s,rt,octane,no light,best quality,illustration,looking at viewer,impasto,canvas,realistic,rea…

【竞技宝】LCK:KT0-3爆冷不敌NS淘汰出局

北京时间2月13日&#xff0c;英雄联盟LCK2025在昨天正式迎来第一阶段的季后赛&#xff0c;首战迎来KT对阵NS&#xff0c;以下是本场比赛的详细战报。 第一局&#xff1a; KT&#xff1a;安蓓萨、大树、沙皇、韦鲁斯、布隆 NS&#xff1a;杰斯、瑟庄妮、阿萝拉、卡莎、泰坦 首…

电脑端调用摄像头拍照:从基础到实现

文章目录 1. 了解navigator.mediaDevices.getUserMedia API2. 创建 HTML 结构3. 编写 JavaScript 代码3.1 打开摄像头3.2 拍照 4. 完整代码5. 测试6. 注意事项及部署 在现代 Web 开发中&#xff0c;调用摄像头进行拍照是一个常见的功能&#xff0c;尤其是在需要用户上传头像、进…

lvs的DR模式

基于Linux的负载均衡集群软件 LVS 全称为Linux Virtual Server,是一款开源的四层(传输层)负载均衡软件 Nginx 支持四层和七层(应用层)负载均衡 HAProxy 和Nginx一样,也可同时支持四层和七层(应用层)负载均衡 基于Linux的高可用集群软件 Keepalived Keepalived是Linux…

STM32 RTC 实时时钟说明

目录 背景 RTC(实时时钟)和后备寄存器 32.768HZ 如何产生1S定时 RTC配置程序 第一次上电RTC配置 第1步、启用备用寄存器外设时钟和PWR外设时钟 第2步、使能RTC和备份寄存器访问 第3步、备份寄存器初始化 第4步、开启LSE 第5步、等待LSE启动后稳定状态 第6步、配置LSE为…

2024年12月电子学会青少年机器人技术等级考试(三级)理论综合真题

202412 青少年等级考试机器人理论真题三级 一、单选题 第 1 题 Arduino UNO/Nano主控板&#xff0c;程序模块如下&#xff0c;该模块运行后&#xff0c;引脚5输出的等效电压为0V&#xff0c;变量i对应的值是&#xff1f;&#xff08; &#xff09; A&#xff1a;0 B&#xff1…

分治中的快速排序(前序遍历)与归并排序(后序遍历)详细对比分析

目录 1. 快速排序&#xff08;前序遍历&#xff09; 核心思想与步骤 关键特性 示例分析 2. 归并排序&#xff08;后序遍历&#xff09; 核心思想与步骤 关键特性 示例分析 3. 对比总结 4. 选择依据与优化策略 5. 实际应用场景 6. 核心差异图示 7. 总结 1. 快速排序…

DeepSeek 助力 Vue 开发:打造丝滑的进度条

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

编译和链接【四】链接详解

文章目录 编译和链接【四】链接详解前言系列文章入口符号表和重定位表链接过程分段组装符号决议重定位 编译和链接【四】链接详解 前言 在我大一的时候&#xff0c; 我使用VC6.0对C语言程序进行编译链接和运行 &#xff0c; 然后我接触了VS&#xff0c; Qt creator等众多IDE&…