【注解和反射】获取类运行时结构

继上一篇博客【注解和反射】类加载器-CSDN博客

目录

七、获取类运行时结构

测试

getFields()和getDeclaredFields()

getMethods()和getDeclaredMethods()


七、获取类运行时结构

获取类运行时结构通常指的是在Java等面向对象编程语言中,使用反射(Reflection)机制来检查类、接口、字段(Field)和方法(Method)等程序元素的能力。这种能力允许你在运行时动态地获取类的信息,并且可以调用类的方法、改变字段的值等。

在Java中,获取类运行时结构主要包括以下几个方面:

  1. 获取Class对象: 要获取类的运行时结构,首先需要获取代表该类的Class对象。这可以通过多种方式实现,例如使用.class语法、Class.forName()方法或通过对象的getClass()方法。

  2. 获取类的名称: 通过Class对象的getName()方法可以获取类的全限定名(包括包名)。

  3. 获取类的修饰符: 使用getModifiers()方法可以获取类的修饰符(如publicabstractfinal等),通常与Modifier.toString()方法结合使用以获取可读的修饰符字符串。

  4. 获取类的父类和实现的接口: 通过getSuperclass()方法可以获取类的直接父类,而getInterfaces()方法则返回当前类实现的接口数组。

  5. 获取类的字段: 使用getDeclaredFields()方法可以获取类中声明的所有字段,无论访问权限如何。而getFields()方法仅返回public字段。

  6. 获取类的方法: 类似地,getDeclaredMethods()方法返回类中声明的所有方法,而getMethods()方法仅返回public方法,包括继承自父类的方法。

  7. 获取类的构造器: 通过getDeclaredConstructors()方法可以获取类的所有构造器,而getConstructors()方法仅返回public构造器。

  8. 获取类的注解: 如果类、方法、字段等上面有注解(Annotation),可以使用getAnnotations()getDeclaredAnnotation()等方法来获取这些注解信息。

  9. 获取类的内部类和接口: 通过getDeclaredClasses()方法可以获取当前类中声明的所有内部类和接口。

  10. 判断类的特性Class类提供了一系列的方法来判断类的特性,如isInterface()isEnum()isAnnotation()isAnonymousClass()isArray()isPrimitive()等。

获取类运行时结构的能力在Java中非常强大,它允许开发者在程序运行时动态地分析和操作类,这在很多场景下都很有用,比如框架设计、单元测试、序列化和反序列化、依赖注入等。然而,使用反射也需要谨慎,因为它可能会破坏封装性,降低性能,并且使代码更加复杂和难以维护。

测试

首先,我们需要定义一个 User 类,

class User{private String name;private int id;private int age;public User(String name, int id, int age) {this.name = name;this.id = id;this.age = age;}public User() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", id=" + id +", age=" + age +'}';}
}

在代码示例中,Test05 类有一个 main 方法,该方法执行了以下操作:

  1. 创建了一个 User 类的对象 user
  2. 通过调用 user.getClass() 获取了 User 类的 Class 对象,并将其存储在变量 c1 中。
  3. 打印了 c1 所代表的类的全名(包名 + 类名)和简单类名(仅类名)。
  4. 打印了一行分隔符 -------
  5. 获取了 c1 所代表的类声明的所有字段(不包括继承的字段),并遍历打印了每个字段的信息。

public class Test05 {public static void main(String[] args) throws ClassNotFoundException {User user = new User();Class c1 = user.getClass();System.out.println(c1.getName());System.out.println(c1.getSimpleName());System.out.println("-------");// Field[] fields = c1.getFields();Field[] fields = c1.getDeclaredFields();for(Field f: fields){System.out.println(f);}}
}

这里是输出结果的详细分析:

  1. System.out.println(c1.getName()); 打印了User类的完全限定名,即包括包名(如果有的话)和类名。因为User类没有指定包名,所以输出就是User

  2. System.out.println(c1.getSimpleName()); 打印了User类的简单名字,也就是不包括包名的类名,所以输出还是User

  3. 在打印了一行分隔符之后,代码通过c1.getDeclaredFields()获取了User类中声明的所有字段,包括privateprotected、默认(包私有)和public字段。在这个例子中,User类有三个private字段:nameidage。这些字段被打印出来,包括它们的访问修饰符、类型、类名和字段名。

getFields()和getDeclaredFields()

在Java的反射API中,getFields()getDeclaredFields()方法都用于获取类的字段,但它们在获取字段的范围和访问权限上有明显的区别:

  1. getFields():

    • 这个方法返回的是当前类及其所有父类(包括Object类)中声明的public字段
    • 它不包括当前类中声明的privateprotected和默认(包私有)访问级别的字段。
    • 如果当前类或其父类中没有public字段,那么这个方法将返回一个长度为0的数组。
  2. getDeclaredFields():

    • 这个方法返回的是当前类中声明的所有字段,无论它们的访问权限是什么(publicprivateprotected或默认)。
    • 它不包括父类中声明的任何字段,只查看当前类的字段。
    • 即使当前类中没有字段,这个方法也会返回一个数组,只不过数组的长度是0。

通常,如果你只对当前类的字段感兴趣,而不关心父类的字段,那么你应该使用getDeclaredFields()。同时,如果你需要访问非public字段,你也需要使用getDeclaredFields(),因为getFields()不会返回这些字段。

另外,值得注意的是,如果你使用getDeclaredFields()获取了非public字段,并且想要访问或修改这些字段的值,你需要先调用Field.setAccessible(true)来允许访问这些字段,否则会抛出IllegalAccessException异常。

getMethods()getDeclaredMethods()

现在,让我们来讨论getMethods()getDeclaredMethods()的区别:

  1. getMethods():

    • 这个方法返回当前类及其所有父类(包括Object类)中声明的所有public方法。
    • 它不包括当前类中声明的privateprotected和默认(包私有)访问级别的方法。
    • 返回的数组包含了从当前类开始,沿着继承链向上直到Object类的所有public方法。
  2. getDeclaredMethods():

    • 这个方法返回当前类中声明的所有方法,无论它们的访问权限是什么(publicprivateprotected或默认)。
    • 它不包括父类中声明的任何方法,只查看当前类的方法。
    • 即使当前类中没有方法,这个方法也会返回一个数组,只不过数组的长度是0。

与字段的情况类似,如果你只对当前类的方法感兴趣,而不关心父类的方法,那么你应该使用getDeclaredMethods()。同时,如果你需要访问非public方法,你也需要使用getDeclaredMethods(),因为getMethods()不会返回这些方法。

同样值得注意的是,如果你使用getDeclaredMethods()获取了非public方法,并且想要调用这些方法,你需要先调用Method.setAccessible(true)来允许访问这些方法,否则会抛出IllegalAccessException异常。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STL——List常用接口模拟实现及其使用

认识list list的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素…

【IDEA】在IntelliJ IDEA中导入Eclipse项目:详细指南

IntelliJ IDEA和Eclipse是两款常用的集成开发环境(IDE),在软件开发中经常会遇到需要在它们之间迁移项目的情况。本文将重点介绍如何在IntelliJ IDEA中导入Eclipse项目,以帮助开发者顺利地迁移他们的项目,并在IntelliJ …

大型语言模型高效推理综述

论文地址:2404.14294.pdf (arxiv.org) 大型语言模型(LLMs)由于在各种任务中的卓越表现而受到广泛关注。然而,LLM推理的大量计算和内存需求给资源受限的部署场景带来了挑战。该领域的努力已经朝着开发旨在提高LLM推理效率的技术方…

RustGUI学习(iced)之小部件(二):如何使用滑动条部件

前言 本专栏是学习Rust的GUI库iced的合集,将介绍iced涉及的各个小部件分别介绍,最后会汇总为一个总的程序。 iced是RustGUI中比较强大的一个,目前处于发展中(即版本可能会改变),本专栏基于版本0.12.1. 概述…

Redis中的慢查询日志(一)

慢查询日志 概述 Redis的慢查询日志功能用于记录执行时间超过给定时长的命令请求,用户可以通过这个功能产生的日志来 监视和优化查询速度。服务器配置有两个和慢查询日志相关的选项: 1.slowlog-log-slower-than选项指定执行时间超过多少微妙(1秒1000 000微妙)的命…

【精】DevOps实战学习CI/CD落地方案#CI篇#

目录 先有个大概了解 基本概念 CI/CD Devops 阿里云效 devops产品 K8s jenkins docker git maven 知行合一,上手操作 实操记录 安装VMware 安装并配置虚拟机 安装并配置docker docker安装 修改镜像源(关键且易出错) CentOS…

低代码信创开发核心技术(四)动态元数据系统设计

一、概述 在当今快速发展的信息技术领域,动态元数据系统扮演着至关重要的角色。它不仅能够提供数据的描述信息,还能动态地适应业务需求的变化,从而提高系统的灵活性和可扩展性。构建一个动态元数据系统意味着我们可以在不重启系统的情况下&a…

Facebook的未知力量:数字世界的新引擎

在数字化的时代,社交媒体已经成为了我们日常生活中不可或缺的一部分,而Facebook作为其中的巨头,其影响力远远超出了我们的想象。但是,Facebook背后隐藏的力量和影响远不止于此,它正逐渐成为数字世界的新引擎&#xff0…

书生·浦语 大模型(学习笔记-5)XTuner 微调 LLM:1.8B、多模态、Agent

目录 一:两种微调 二、数据的一生 三、微调方案 四、XTuner 五、InternLM2 1.8B模型(相关知识) 一:两种微调 增量与训练和指令微调的区别 二、数据的一生 原始数据转换为标准格式数据 添加对话模板,直接调用即可…

操作系统课程--考纲要求

第一/二次课: 绪论 【学习内容与目标】 1、操作系统目标及定义 掌握操作系统的设置目标,理解并掌握操作系统的定义,了解操作系统的地位以及从资源管理者角度和用户角度了解操作系统的组成。 2、 操作系统的特征与功能 掌握操作系统的特征&…

github Copilot的使用总结

1. 代码建议和补全 GitHub Copilot 的基本使用涉及编写代码时的实时代码建议和补全。一旦你已经安装并配置好 GitHub Copilot 插件,你可以在支持的编辑器(如 Visual Studio Code)中开始使用 Copilot。以下是一些基本的使用步骤: …

RK3588S和ARM阵列服务器在虚拟化云平台的应用

RK3588是瑞芯微2021年底推出的首款高端8nm旗舰芯片,而RK3588S 则是针对消费端市场在RK3588基础上缩减了部分外围接口,CPU、GPU和NPU等主要参数得到了保留,主要应用范围为高端ARM平板、ARM笔电产品,会议平板类、ARM服务器、智能机器…

信息系统项目管理师——第7章项目立项管理

本章考选择题2-3分,案例和论文均有可能作为领域考试。 项目建议与立项申请♥♥♥♥♥ 立项申请的概念 立项申请又称为项目建议书,是项目建设单位向上级主管部门提交项目申请时所必须的文 件,是该项目建设筹建单位根据国民经济的发展、国家…

JavaWeb过滤器

Javaweb过滤器是一种用于在Servlet处理请求之前或之后对请求进行预处理或后处理的组件。过滤器可以用于拦截请求、修改请求参数、过滤响应内容等操作。其主要作用包括: 拦截请求:过滤器可以拦截客户端请求,对请求进行验证、过滤或修改&#x…

Java基础之JVM对象内存分配机制简介

一 对象内存分配 1.1 运行时数据区域 1.2 常见java应用启动JVM参数: -Xss:每个线程的栈大小(单位kb)-Xms:堆的初始大小,默认物理内存的1/64,示例:-Xms:4g -Xms:10m-Xmx:堆的最大可用大小,默认物…

水库大坝安全白蚁监测系统解决方案

一、系统背景 白蚁作为河岸生态系统中的重要病害,不仅会导致水库大坝外部环境发生改变,甚至会引发水库大坝破坏,进而导致自身结构失去稳定性,严重影响水库大坝的正常运行。因此,治理水库大坝白蚁是确保水库大坝工程顺利…

HTTP与HTTPS 对比,区别详解(2024-04-25)

一、简介 HTTP(超文本传输协议,Hypertext Transfer Protocol)是一种用于从网络传输超文本到本地浏览器的传输协议。它定义了客户端与服务器之间请求和响应的格式。HTTP 工作在 TCP/IP 模型之上,通常使用端口 80。 HTTPS&#xf…

【Hadoop】- MapReduce YARN 初体验[9]

目录 提交MapReduce程序至YARN运行 1、提交wordcount示例程序 1.1、先准备words.txt文件上传到hdfs,文件内容如下: 1.2、在hdfs中创建两个文件夹,分别为/input、/output 1.3、将创建好的words.txt文件上传到hdfs中/input 1.4、提交MapR…

区块链技术与应用学习笔记(8-9节)——北大肖臻课程

目录 8.挖矿 对于全节点和轻节点思考问题? ①全节点在比特币的主要作用? ②挖矿时当监听到别人已经挖出区块并且延申了最长合法链此时应该立刻放弃当前区块在 本地重新组装一个指向最后这个新合法区块的候选区块,重新开始挖矿。节点这么做…

「React Native」为什么要选择 React Native 作为的跨端方案

文章目录 前言一、常见因素二、举个栗子2.1 项目背景2.2 为什么选择 React Native2.3 项目实施2.4 成果总结 前言 没有完美的跨端技术,只有适合的场景。脱离适用场景去谈跨端技术没有什么意义。 一、常见因素 共享代码库: React Native 允许开发者编写…