【JavaSE系列】反射机制

目录

前言

一、概述

二、获取Class对象

三、反射构造方法

1. 获取构造方法

2. 获取修饰符、名称和形参

3. 创建对象

四、反射成员变量 

1. 获取成员变量

2. 获取修饰符、名称和类型

3. 赋值/获取值

五、 反射成员方法

1. 获取成员方法

2. 获取修饰符、形参、返回值和异常

3. 运行成员方法

总结


前言

  在当今的软件开发领域,灵活性和可扩展性成为了软件设计的重要考量因素。Java反射机制作为实现这一目标的强大工具之一,为开发人员提供了在运行时动态获取类的信息或动态调用对象的方法的能力。通过使用反射,开发人员可以在不知道具体实现细节的情况下,操作类、构造函数、方法及字段等。

一、概述

  Java反射机制是指在运行时动态获取类的信息或动态调用对象的方法、修改属性等操作。主要核心就是Class类、Constructor类、Field类、Method类等API。 反射机制主要应用于框架开发、动态代理、ORM框架、JDBC驱动等方面。通过反射机制,程序员能够获得在编译期间不被知晓的类、属性、方法等信息。但是反射机制的性能较低,常常被认为是一种牺牲性能换取灵活性的实现方式。

二、获取Class对象

  在Java中,我们有三种方式获取Class对象,下面是这三种方式:

方式 示例使用时机
方式一:使用Class类的forName()方法Class clazz = Class.forName("java.lang.Object");源代码阶段
方式二:使用“类.class”语法Class clazz = Object.class;加载阶段
方式三:调用Object类的getClass()方法

Object obj = new Object();

Class clazz = obj.getClass();

运行阶段

  这三种方式其实就对应Java里面三种不同的阶段,如果我想创建一个类的对象,是分以下三个阶段的:第一个阶段,要先编写Java文件,然后把他编译成.class字节码文件,这个阶段还没有把代码加载到内存的,只是在硬盘里面进行的操作,所以这个阶段我们也叫做源代码阶段,这个阶段我们会用方式一去获取字节码文件对象。接下来要运行代码了,是不是首先要把这个类的字节码文件加载到内存?这个阶段我们叫做加载阶段,在这个阶段我们会用方式二。接下来去内存当中创建这个类的对象,比如A a = new A(),此时就叫做运行阶段,这个阶段用方式三。下图是对这三个方式的进一步使用的示例:

三、反射构造方法

1. 获取构造方法

  Class类中有四种用于获取构造方法的方法,这四种方法的简单描述如下所示:

方法描述
Constructor<?>[] getConstructors();返回所有“公共”构造方法对象的数组
Constructor<?>[] getDeclaredConstructors();返回所有构造方法对象的数组
Constructor getConstructor(Class<?>…parameterTypes);返回单个“公共”构造方法对象
Constructor getDeclaredConstructor(Class<?>…parameterTypes);返回单个构造方法对象

  下面,我们可以编写一个Student对象,该类中的属性和相关方法如下所示,后面的反射示例均会使用到这个类:

public class Student {private String name;private int age;public String gender;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}protected Student(int age) {this.age = age;}private Student(String name) {this.name = name;}public String getName() {return this.name;}public void setName(String name) {this.name = name;}public int getAge() {return this.age;}public void setAge(int age) {this.age = age;}void sayHello() {System.out.println("学生说你好!");}private String sayHello(String str) throws RuntimeException {System.out.println("你好你好!");return str;}}

  下面我们编写Java代码来测试上面提到的四种获取构造方法的代码:

public static void main(String[] args) throws NoSuchMethodException {Class<Student> studentClass = Student.class;// 方式一Constructor<?>[] constructors = studentClass.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println(constructor); // 仅输出public修饰的构造方法}System.out.println("==================================================================");// 方式二Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();for (Constructor<?> constructor : declaredConstructors) {System.out.println(constructor);}System.out.println("==================================================================");// 方式三Constructor<Student> constructor = studentClass.getConstructor(String.class, int.class);System.out.println(constructor); // 仅能获取public修饰的构造方法,如果不是,则会报错System.out.println("==================================================================");// 方式四Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(int.class);System.out.println(declaredConstructor);
}

  测试结果如下图所示:

2. 获取修饰符、名称和形参

  如何获取构造方法上的修饰符、名称和形参呢?下面是我们的测试代码:

public static void main(String[] args) throws NoSuchMethodException {Class<Student> studentClass = Student.class;Constructor<Student> constructor = studentClass.getConstructor(String.class, int.class);int modifiers = constructor.getModifiers();System.out.println("修饰符整数标识:" + modifiers);String stringModifiers = Modifier.toString(modifiers);System.out.println(stringModifiers);System.out.println("===========================================");String name = constructor.getName();System.out.println(name); // 打印构造方法名称System.out.println("===========================================");Class<?>[] parameterTypes = constructor.getParameterTypes();for (Class<?> parameterType : parameterTypes) {System.out.println(parameterType); // 打印参数类型}System.out.println("===========================================");Parameter[] parameters = constructor.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter); // 打印参数名称}
}

  测试结果如下图所示:

3. 创建对象

  Constructor类中用于创建对象的方法有:

方法描述
T newInstance(Object… initargs)根据指定构造方法创建对象
setAccessible(boolean flag)设置为true,表示取消访问检查

  下面是一个示例代码:

public static void main(String[] args) throws Exception {Class<Student> studentClass = Student.class;Constructor<Student> constructor = studentClass.getDeclaredConstructor(String.class);constructor.setAccessible(true); // 取消访问检查Student student = constructor.newInstance("张三");System.out.println(student);
}

  运行结果如下图所示:

四、反射成员变量 

1. 获取成员变量

  Class类中用于获取成员变量的方法有四种,这四类方法如下:

方法描述
Field[] getFields();返回所有"公共"成员变量对象的数组
Field[] getDeclaredFields();返回所有成员变量对象的数组
Field getField(String name);返回单个公共成员变量对象
Field getDeclaredField(String name);返回单个成员变量对象

  下面我们编写Java代码对这四个方法进行测试:

public static void main(String[] args) throws NoSuchFieldException {Class<Student> studentClass = Student.class;// 方式一Field[] fields = studentClass.getFields();for (Field field : fields) {System.out.println(field);}System.out.println("===========================================================================");// 方式二Field[] declaredFields = studentClass.getDeclaredFields();for (Field field : declaredFields) {System.out.println(field);}System.out.println("===========================================================================");// 方式三Field gender = studentClass.getField("gender");System.out.println(gender);System.out.println("===========================================================================");// 方式四Field name = studentClass.getDeclaredField("name");System.out.println(name);
}

  代码运行结果如下图所示:

2. 获取修饰符、名称和类型

  如何获取成员变量上的修饰符、名称和形参呢?下面是我们的测试代码:

public static void main(String[] args) throws NoSuchFieldException {Class<Student> studentClass = Student.class;Field gender = studentClass.getField("gender");System.out.println(Modifier.toString(gender.getModifiers())); // 修饰符System.out.println(gender.getName()); // 名称System.out.println(gender.getType()); // 类型
}

  测试结果如下图所示:

 

3. 赋值/获取值

  Field类中用于赋值和获取值的方法:

方法描述
void set(Object obj, Object value)赋值
Object get(Object obj)获取值

  下面是一个示例代码: 

public static void main(String[] args) throws Exception {Student student = new Student("张三", 18);Class<? extends Student> studentClass = student.getClass();Field name = studentClass.getDeclaredField("name");name.setAccessible(true);Object oldValue = name.get(student);System.out.println(oldValue); // 获取值name.set(student, "李四"); // 设置值System.out.println(student);
}

  运行结果如下: 

五、 反射成员方法

1. 获取成员方法

  Class类中用于获取成员方法的方法有四个,这四个方法如下所示:

方法描述
Method[] getMethods();返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods();返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>… parameterTypes);返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?> … parameterTypes);返回单个成员方法对象

  下面是这四个方法的使用示例代码: 

public static void main(String[] args) throws NoSuchMethodException {// 方式一Class<Student> studentClass = Student.class;Method[] methods = studentClass.getMethods();for (Method method : methods) {System.out.println(method);}System.out.println("=======================================================================");// 方式二Method[] declaredMethods = studentClass.getDeclaredMethods();for (Method method : declaredMethods) {System.out.println(method);}System.out.println("=======================================================================");// 方式三Method setName = studentClass.getMethod("setName", String.class);System.out.println(setName);System.out.println("=======================================================================");// 方式四Method sayHello = studentClass.getDeclaredMethod("sayHello");System.out.println(sayHello);
}

  运行结果如下图所示: 

2. 获取修饰符、形参、返回值和异常

  如何获取成员变量上的修饰符、形参、返回值和异常呢?下面是我们的测试代码:

public static void main(String[] args) throws NoSuchMethodException {Class<Student> studentClass = Student.class;Method sayHello = studentClass.getDeclaredMethod("sayHello", String.class);System.out.println(Modifier.toString(sayHello.getModifiers())); // 修饰符System.out.println("=============================================");Class<?>[] parameterTypes = sayHello.getParameterTypes();for (Class<?> parameterType : parameterTypes) {System.out.println(parameterType); // 形参类型}System.out.println("=============================================");Parameter[] parameters = sayHello.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter); // 形参}System.out.println("=============================================");Class<?> returnType = sayHello.getReturnType();System.out.println(returnType); // 返回值类型System.out.println("=============================================");Class<?>[] exceptionTypes = sayHello.getExceptionTypes();for (Class<?> exceptionType : exceptionTypes) {System.out.println(exceptionType);} // 异常
}

  测试结果如下图所示:

 

补充:我们还可以反射方法上的注解,进一步提高程序的扩展性,下面是一篇参考博文:

Java Reflect - 利用反射获取类上的注解

3. 运行成员方法

  Method类中用于创建对象的方法如下所示:

方法描述
Object invoke(Object obj, Object… args);

运行方法

参数一:用obj对象调用该方法

参数二:调用方法的传递的参数(如果没有就不写)

返回值:方法的返回值(如果没有就不写)

  下面是我们的测试代码: 

public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {Student student = new Student();Class<Student> studentClass = Student.class;Method sayHello = studentClass.getDeclaredMethod("sayHello", String.class);sayHello.setAccessible(true);Object res = sayHello.invoke(student, "人生入戏");System.out.println(res);
}

  运行结果如下:

 

总结

  本文探讨了Java反射机制的基础知识,包括获取Class对象的不同方式、反射构造方法、获取成员方法和成员变量等。通过一系列的实际代码示例,我们展示了如何利用反射机制来动态地获取类的信息、创建对象、获取构造方法和成员方法的细节、以及如何对成员变量进行操作。尽管反射机制为Java开发带来了极大的灵活性,但也应注意到它可能会带来的性能影响。因此,在实际项目中,应当合理使用反射,确保在灵活性与性能之间取得良好的平衡。掌握反射机制不仅有助于深入理解Java语言的内部工作原理,而且还能帮助开发者更有效地使用现有的框架和技术栈,提高软件的可维护性和扩展性。 

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

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

相关文章

远程访问电脑共享文件

远程访问电脑共享文件&#xff0c;可以通过多种方法实现&#xff0c;每种方法都有其特点和适用场景。以下是一些常见的方法及其步骤&#xff1a; 一、使用Microsoft远程桌面 启用远程桌面&#xff1a; 在目标电脑上&#xff0c;打开“开始”菜单&#xff0c;选择“设置”>“…

【网络安全】PHP配置注入漏洞

未经许可&#xff0c;不得转载。 文章目录 正文 正文 前提&#xff1a;通过探测等方式发现某个 PHP 文件存在 PHPRC 参数&#xff1a; curl "https://xxx.com/about.php?PHPRC/dev/fd/0" --data-binary auto_prepend_file"/etc/passwd"PHPRC 用于指定 P…

CTF——简单的《WEB》

文章目录 一、WEB1、easysql2、baby_web3、baby_sql4、upload_easy5、easygame拓展1.1拓展1.2 6、ht_ssti7、包容乃大 一、WEB 1、easysql 题目描述&#xff1a; sql注入漏洞 1.常用的sql注入测试语句 2.sql注入bypass 解题思路 这边提示基本给的也很完整的&#xff0c;不…

NFT Insider #147:Sandbox 人物化身九月奖励上线;Catizen 付费用户突破百万

市场数据 加密艺术及收藏品新闻 Doodles 动画特别剧《Dullsville and The Doodleverse》在多伦多国际电影节首映 Doodles 最近在多伦多国际电影节&#xff08;TIFF&#xff09;首映了其动画特别剧《Dullsville and The Doodleverse》&#xff0c;这是该品牌的一个重要里程碑。…

无人机几种常见的避障系统!!!

1. 视觉避障系统 工作原理&#xff1a; 视觉避障系统通过安装在无人机上的摄像头捕捉周围环境的图像&#xff0c;利用计算机视觉技术对图像进行处理和分析&#xff0c;提取出障碍物的信息。 通过对障碍物的识别和分类&#xff0c;无人机可以判断出障碍物的性质和危险程度&am…

鸿蒙开发基础

页面跳转 了解代码初始结构 /*** 装饰器&#xff1a;用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊的含义。* Entry&#xff1a;表示该自定义组件为入口组件 * Component&#xff1a;表示自定义组件* State&#xff1a;表示组件中的状态变量&#xff0c;状态变量变…

抓机遇,创发展︱2025 第十二届广州国际汽车零部件加工技术及汽车模具展览会,零部件国产浪潮不可阻挡

抓机遇&#xff0c;创发展︱2025 第十二届广州国际汽车零部件加工技术及汽车模具展览会&#xff0c;零部件国产浪潮不可阻挡 汽车零部件行业是汽车工业发展的基础&#xff0c;是支撑汽车工业持续稳步发展前提条件。随着经济全球化和市场一体化进程的推进&#xff0c;汽车零部件…

YOLOv5改进 | 模块缝合 | C3 融合Self-Calibrated Convolutions丰富特征图【CVPR2020】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv5入门 改…

37拼购:电商新风尚,共享双赢的购物革命

随着2024年电商市场的日益繁荣&#xff0c;商品海洋中的同质化问题愈发严峻&#xff0c;消费者在茫茫商海中寻觅独特价值的难度陡增。在此背景下&#xff0c;一种名为“37悦享拼”的创新电商模式横空出世&#xff0c;它巧妙融合了私域社交与电商精髓&#xff0c;旨在打破传统壁…

【Go】-Gin框架

目录 Gin框架简介 简单示例 Gin渲染 HTML渲染 自定义模板函数 静态文件处理 使用模板继承 JSON渲染和XML渲染 获取参数 获取querystring参数 获取form参数 获取Path参数 c.Params.Get c.Params() 参数绑定 文件上传 单个文件上传 参数 多个文件上传 重定向…

无人机应用新纪元:图形工作站配置推荐与硬件解析

低空经济作为国家新兴的战略性产业&#xff0c;正逐步成为经济高质量发展的新动力。据统计&#xff0c;2023年中国低空经济规模达到5059.5亿元&#xff0c;增速为33.8%&#xff0c;预计到2026年有望突破万亿元大关。政府对低空经济的发展高度重视&#xff0c;不仅出台了相关法规…

Ubuntu22.04系统安装opencv步骤简述及问题解决方法

前言 opencv是一个功能强大、开源且跨平台的计算机视觉库&#xff0c;适用于多种编程语言和操作系统&#xff0c;能够帮助开发者构建各种视觉项目。其模块众多&#xff0c;提供了诸多功能&#xff0c;能够进行图像处理、视频处理等等。比如&#xff1a;Highgui模块提供图像用户…

OSSEC搭建与环境配置Ubuntu

尝试使用Ubuntu配置了OSSEC&#xff0c;碰见很多问题并解决了&#xff0c;发表博客让后来者不要踩那么多坑 环境 &#xff1a; server &#xff1a;Ubuntu22.04 64位 内存4GB 处理器4 硬盘60G agent: 1.Windows11 64位 2.Ubuntu22.04 64位 服务端配置 一、配置安装依赖项&…

电源模块测试系统中都可以定制哪些内容?

在电源测试系统中&#xff0c;可以定制的内容相当广泛&#xff0c;以满足不同客户、不同应用场景下的特定需求。以下是一些常见的可定制内容&#xff1a; 1. 测试项目 对于电源模块的基础测试项目而言&#xff0c;一般都无需定制基础测试项目&#xff0c;因为电源模块测试的基…

(k8s)kubernetes 挂载 minio csi 的方式(pod挂载pvc存在csi驱动问题,挂载不上)

一、安装Minio&#xff08;Minio分布式集群搭建部署_minio集群最少几台-CSDN博客&#xff09; 生成accessKeyID和secretAccessKey&#xff1a; 二、安装csi-s3插件(在k8s集群上) 首先我们把插件的yaml文件都下载下来&#xff0c;为了保证版本测试的一致性&#xff0c;我们下载…

idea中java及java web项目的常见问题

1、乱码问题&#xff0c;主要有几处地方&#xff0c;需要检查。 ①确保文件编码&#xff0c;其实主要就是在idea启动文件中&#xff0c;增加了 -Dfile.encodingUTF-8的设置 ②编辑器默认编码&#xff0c;都改为UTF-8 ③Tomcat的运行配置&#xff0c;编码也改为UTF-8,同样使用…

Excel文档的读取(1)

熟悉使用Excel的同学应该都知道&#xff0c;在单个Excel表格里想要分商品计算总销售额&#xff0c;使用数据透视表也可以非常快速方便的获得结果。但当有非常大量的Excel文件需要处理时&#xff0c;每一个Excel文件单独去做数据透视也会消耗大量的时间。就算使用Power Query这样…

TCP套接字【网络】

文章目录 代码 创建套接字&#xff1a;&#xff08;TCP/UDP) int socket(int domain, int type, int protocol);inet_aton&#xff0c;将字符串IP转换成整数IP int inet_aton(const char *cp, struct in_addr *inp);监听套接字&#xff1a;&#xff08;TCP&#xff0c;服务器…

Vue - 详细介绍vue-qr在线生成二维码组件(Vue2 Vue3)

Vue - 详细介绍vue-qr在线生成二维码组件&#xff08;Vue2 & Vue3&#xff09; 在对于二维码生成中有许多组件&#xff0c;下面介绍关于自定义比较高的vue-qr组件&#xff0c;能自定义设置背景颜色、背景图片、背景Gif图、实点和空白区的颜色、中心Logo的图片和边距。 一…

Windows 的 docker 删除容器后 WSL2 磁盘空间不释放的问题

1&#xff1a;Windows 的 docker 删除容器后 WSL2 磁盘空间不释放的问题&#xff0c;成功搞定 见这里的文章&#xff1a; https://blog.csdn.net/ppppppppila/article/details/139653675 2&#xff1a; 重装Docker desktop 或者 当打开Docker Desktop时候&#xff0c;启动dock…