反射 - - - - - - - - 内省【精细】

1、概念

Java内省机制(Introspection)是一种访问Java Bean属性的方式,它允许程序在运行时获取和设置Java对象的属性。通过内省机制,程序可以在运行时获取对象的属性名、类型和值,并动态地设置对象的属性值。内省机制为Java反射机制的一个重要应用,使得Java Bean对象可以更加灵活地被访问和处理。

2、Java内省的作用

  1. 动态访问Java对象的属性和方法:Java内省可以在运行时动态获取Java对象的属性和方法信息,并访问其属性值和调用其方法。
  2. 避免硬编码对象的属性和方法名称:Java内省可以通过反射机制避免硬编码对象的属性和方法名称,从而使程序更加灵活和可扩展。
  3. 提高代码的可读性和可维护性:Java内省可以使代码更加简洁和易读,同时也方便了代码的维护和修改。
  4. 支持动态代理和AOP编程:Java内省可以支持动态代理和AOP编程,从而实现更加灵活和可扩展的编程。

3、Java内省的实现机制

Java内省的实现机制基于Java的反射机制。在Java中,每个类都有一个Class对象,可以通过这个Class对象获取类的各种信息,包括类的名称、构造方法、属性和方法等。Java内省通过分析Class对象来获取Java对象的属性和方法信息,并通过反射机制访问其属性值和调用其方法。

二、Java内省的核心类

Java内省的核心类包括 IntrospectorBeanInfoPropertyDescriptorMethodDescriptor 和IntrospectionException

1、Introspector类

Introspector 是一个工具类,它提供了一种标准方法来了解目标 Java Bean 支持的属性、事件和方法。通过调用Introspector.getBeanInfo()方法,可以获取封装 JavaBean 相关信息的 BeanInfo 对象,如下所示:

(1)static BeanInfo getBeanInfo(Class<?> beanClass)

获取beanClass对应的 Javabean 对象的 BeanInfo 的封装

(2)static BeanInfo getBeanInfo(Class<?> beanClass, Class<?> stopClass)

获取 beanClass 对应的 Javabean 对象的 BeanInfo 的封装。其中,stopClass 指定停止分析(解析)的基类。分析中将忽略 stopClass 或其基类中的任何方法、属性、事件。

2、BeanInfo接口

BeanInfo 对象是 Java 内省的核心对象之一,用于描述JavaBean的所有属性和方法信息。它包含了一个或多个PropertyDescriptor对象和MethodDescriptor对象,用于描述JavaBean的所有属性和方法信息。BeanInfo接口提供了一组用于访问JavaBean的属性和方法信息的方法,如下所示:

getPropertyDescriptors()

返回一个PropertyDescriptor数组,用于描述JavaBean的所有属性信息。每个PropertyDescriptor对象包含了一个属性的名称、类型和读写方法等信息。

getMethodDescriptors()

返回一个MethodDescriptor数组,用于描述JavaBean的所有方法信息。每个MethodDescriptor对象包含了一个方法的名称、参数类型和返回值类型等信息。

3、PropertyDescriptor类

注意:内省是根据标准的 setter 或 getter 方法来获取属性信息。

如果在类中,定义了属性,但并没有提供标准的 setter 或 getter 方法,则读取不到任何属性信息;反之,如果在类中,没有定义属性,但提供了标准的 setter 或 getter 方法,则可以读取对应的属性信息。例如:Object 类通过 getter 方法:getClass(),可以读取到 class 属性。

PropertyDescriptor类是用于描述 JavaBean 的一个属性信息。它包含了一个属性的名称、类型和读写方法等信息。PropertyDescriptor 类提供了一组用于访问 JavaBean 的属性信息的方法,如下所示:

  • getName():方法返回属性的名称。

  • getPropertyType():返回属性的类型。

    • isPrimitive():判断数据类型是否为基本数据类型
  • getReadMethod():返回属性的读方法,即getter方法。

  • getWriteMethod():返回属性的写方法,即setter方法。

4、MethodDescriptor类

MethodDescriptor类是用于描述JavaBean的一个方法信息。它包含了一个方法的名称、参数类型和返回值类型等信息。MethodDescriptor类提供了一组用于访问JavaBean的方法信息的方法,如下所示:

  • getName():返回方法的名称。
  • getParameterTypes():返回方法的参数类型数组。
  • getReturnType():返回方法的返回值类型。

调用 getMethod() 方法可以获得指定方法的 Method 类型对象,然后就可以利用反射执行指定的方法。

5、IntrospectionException类

IntrospectionException类是 Java 内省过程中可能会抛出的异常类。它表示 Java 内省过程中发生的异常情况,例如 JavaBean 的属性或方法不存在、不合法的属性或方法等。

三、Java内省的基本用法

下面是一个简单的示例代码,演示如何使用 Java 内省获取 JavaBean 的属性和方法信息,并访问和设置属性值。内省的具体操作步骤如下:

在 Java 内省中,一个 JavaBean 是一个符合特定规范的 Java 对象,该规范要求该对象具有无参构造函数以及一组可读可写的属性。JavaBean 的属性通常通过 get 和 set 方法进行访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*** 第一:定义 JavaBean 对象** @author zqx* @date 2023-03-04*/
public class Person {private String name;private int age;// setter/getter
}/*** JavaBean 继承** @author zqx* @date 2023-03-04*/
public class Staff extends Person {private String department;private double salary;// setter/getter
}

1、获取 JavaBean 的 BeanInfo 对象

BeanInfo 对象表示的是 JavaBean 的信息,可以通过 Introspector 类调用相关方法获得的。

1
2
3
4
5
BeanInfo beanInfo = Introspector.getBeanInfo(类.class);
BeanInfo beanInfo = Introspector.getBeanInfo(子类.class,父类.class);BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
BeanInfo beanInfo = Introspector.getBeanInfo(Staff.class,Person.class);

2、获取 JavaBean 的属性和方法信息

可以通过 BeanInfo 类的 getPropertyDescriptors() 方法和 getMethodDescriptors() 方法获取 JavaBean 的所有属性和方法信息,然后遍历属性和方法描述符来获取具体的属性和方法信息。

1)获取属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1.获取属性描述器
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();// 2.遍历属性描述器
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {// 获取属性名称String propertyName = propertyDescriptor.getName();// 获取属性的数据类型Class<?> propertyType = propertyDescriptor.getPropertyType();System.out.println("属性的修饰符:" + propertyType.getModifiers());System.out.println("属性的修饰符:" + Modifier.toString(propertyType.getModifiers()));System.out.println("属性的数据类型:" + propertyType.getName());System.out.println("属性的数据类型:" + propertyType.getSimpleName());System.out.println("属性的数据类型是否为基本类型:"+propertyType.isPrimitive());System.out.println("属性名称:" + propertyName);System.out.println("----------------");
}
2)获取方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 1.获取方法描述器
MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();// 2.遍历方法描述器
for (MethodDescriptor methodDescriptor : methodDescriptors) {// 输出方法名称、参数类型和返回值类型int modifiers = methodDescriptor.getMethod().getModifiers();System.out.println("方法修饰符:" + Modifier.toString(modifiers));System.out.println("方法返回值:" + methodDescriptor.getMethod().getReturnType().getName());System.out.println("方法名称:" + methodDescriptor.getName());System.out.println("方法名称:" + methodDescriptor.getMethod().getName());System.out.println("方法参数:");Class<?>[] parameterTypes = methodDescriptor.getMethod().getParameterTypes();for (Class<?> parameterType : parameterTypes) {System.out.println("\t参数类型:" + parameterType.getName());System.out.println("\t参数类型:" + parameterType.getSimpleName());}System.out.println("----------------");
}

3、访问 JavaBean 的属性值

可以通过 PropertyDescriptor 类的 getReadMethod() 方法获取 JavaBean 的 getter 方法,然后通过反射机制调用getter方法获取属性值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 实例化 Person 对象 - JavaBean 对象
Person bean = new Person("zing", 18);// 循环遍历 Person 对象的所有属性
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {// 获取 Person 对象的属性名称String propertyName = propertyDescriptor.getName();// 获取Person对象的写方法 -- getter方法Method readMethod = propertyDescriptor.getReadMethod();// 如果属性是可读的,则输出属性值 - getter方法if (readMethod != null) {Object value = readMethod.invoke(bean);System.out.println(propertyName + "=" + value);}
}

4、设置 JavaBean 的属性值

可以通过 PropertyDescriptor 类的 getWriteMethod() 方法获取 JavaBean 的 setter 方法,然后通过反射机制调用setter方法设置属性值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 实例化 Person 对象 - JavaBean 对象
Person bean = new Person();// 循环遍历 Person 对象的所有属性
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {// 获取 Person 对象的属性名称String propertyName = propertyDescriptor.getName();// 获取 Person 对象的写方法 -- setter方法Method writeMethod = propertyDescriptor.getWriteMethod();// 匹配 Person 对象的属性,调用可写方法并设置相关的数据if ("name".equals(propertyName)) {writeMethod.invoke(bean, "zing");} else if ("age".equals(propertyName)) {writeMethod.invoke(bean, 18);}
}System.out.println(bean);

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 实例化Person对象 - JavaBean对象
Person bean = Person.class.getConstructor().newInstance();// 实例化属性描述器,并指定属性名称
PropertyDescriptor nameProperty = new PropertyDescriptor("name", Person.class);
PropertyDescriptor ageProperty = new PropertyDescriptor("age", Person.class);// 获取 setter 方法,并调用 setter 方法初始化 JavaBean 对象
Method setNameMethod = nameProperty.getWriteMethod();
setNameMethod.invoke(bean, "李四");ageProperty.getWriteMethod().invoke(bean,18);System.out.println(bean);

四、Java内省的应用场景

Java内省广泛应用于Java GUI开发和Web开发中。在Java GUI开发中,常常需要对各种Swing组件进行布局、样式和事件处理等操作,而Java内省正是为此提供了非常便捷的方式。例如,我们可以使用Java内省获取一个JButton对象的所有属性和方法信息,并通过反射机制动态地修改和调用这些属性和方法,实现各种自定义功能。

在Web开发中,Java内省也被广泛应用于各种框架和组件中,例如Spring框架中的BeanWrapper和BeanUtils等工具类,以及Struts框架中的BeanUtils等工具类。这些工具类都是基于Java内省实现的,可以方便地对Java对象进行属性的读取、设置和复制等操作,减少了开发人员的工作量,提高了开发效率。

除了Java GUI和Web开发外,Java内省还有其他许多应用场景。例如,在Java数据库开发中,我们常常需要将ResultSet对象中的数据映射到Java对象中,而Java内省可以帮助我们动态地实现这一过程;在Java序列化和反序列化中,Java内省也被广泛应用于自定义的序列化和反序列化过程中,以实现更加灵活和高效的数据传输。

五、Java内省的优缺点

Java内省作为Java反射机制的一部分,具有许多优点和缺点。

1、优点

  1. 方便:Java内省提供了一种便捷的方式,可以通过BeanInfo、PropertyDescriptor和MethodDescriptor等类来动态地访问Java对象的属性和方法,而不需要手动编写大量的反射代码。
  2. 易用:Java内省提供了一组简单易用的API,使得开发人员可以方便地读取、设置和复制Java对象的属性。
  3. 高效:相比于纯反射机制,Java内省的性能更高,因为它缓存了Java类的属性和方法信息,并且避免了多次调用反射机制。
  4. 安全:Java内省在访问Java对象的属性和方法时,会对访问权限进行检查,确保访问的属性和方法是可访问的。

2、缺点

  1. 局限性:Java内省只能访问JavaBean中的属性和方法,无法访问其他类型的对象。
  2. 可读性差:由于Java内省需要使用PropertyDescriptor和MethodDescriptor等类来访问JavaBean中的属性和方法,因此代码可读性不如直接使用JavaBean的属性和方法。
  3. 不够灵活:由于Java内省是基于反射机制实现的,因此在某些场景下,需要使用纯反射机制来访问Java对象的属性和方法,才能实现更加灵活的操作。

六、总结

Java内省是Java反射机制的一部分,提供了一种便捷的方式来访问JavaBean中的属性和方法。通过BeanInfo、PropertyDescriptor和MethodDescriptor等类,我们可以动态地访问JavaBean中的属性和方法,并通过反射机制读取、设置和复制Java对象的属性。Java内省具有方便、易用、高效和安全等优点,但也存在一些局限性和缺点。在实际开发中,需要根据具体的业务场景选择合适的访问方式,以实现更加高效和灵活的操作。

在使用Java内省时,需要注意一些细节。例如,Java内省只能访问JavaBean中的属性和方法,因此需要遵循JavaBean的命名规范,并且将属性的get和set方法定义为public,以便Java内省能够访问。

此外,在访问JavaBean的属性和方法时,需要注意属性和方法的类型和参数类型是否匹配,以避免出现类型转换异常和其他运行时异常。

最后,Java内省虽然具有许多优点,但也不是万能的,有些场景下可能需要使用其他的访问方式。例如,在访问非JavaBean类型的对象或者需要实现更加灵活的访问时,可能需要使用纯反射机制或者其他的访问方式。

总之,Java内省作为Java反射机制的一部分,是Java开发中的一个重要工具。掌握Java内省的使用方法,可以帮助我们更加高效、方便地访问Java对象的属性和方法,提高开发效率,减少出错的可能性。

另外,Java内省还可以与其他Java技术结合使用,实现更加强大的功能。例如,可以将Java内省和JavaFX结合使用,实现JavaFX的数据绑定和动态UI更新。也可以将Java内省和Spring框架结合使用,实现Spring的依赖注入和动态代理等功能。

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

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

相关文章

骑砍2霸主MOD开发(8)-action_sets.xml骨骼动画

一.action_sets.xml 1.文件目录:Modules\Native\ModuleData\action_sets.xml 2.action_set(骨骼动画animation) action1 action2 action3 3.通过在action_set中配置skeleton,人,马匹,牛,羊等骨架 二.使用编辑器修改动作 三.骨架&骨骼&骨骼动画 1.骨架skeleton Skele…

企业微信hook接口协议,根据手机号搜索联系人

根据手机号搜索联系人 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信 请求示例 {"uuid":"3240fde0-45e2-48c0-90e8-cb098d0ebe43","phoneNumber":"1357xxxx" } 返回示例 {"data&q…

opencv可视化图片-----c++

可视化图片 #include <opencv2/opencv.hpp> #include <opencv2/core.hpp> #include <filesystem>// 将数据类型转换为字符串 std::string opencvTool::type2str(int type) {std::string r;uchar depth type & CV_MAT_DEPTH_MASK;uchar chans 1 (typ…

rust是否可以用于8051单片机开发工作?

目前&#xff0c;Rust 在嵌入式领域的发展主要集中在一些常见的架构上&#xff0c;如ARM Cortex-M&#xff08;包括STM32系列&#xff09;、RISC-V等。我这里有一套嵌入式入门教程&#xff0c;不仅包含了详细的视频 讲解&#xff0c;项目实战。如果你渴望学习嵌入式&#xff0c…

递归、搜索与回溯算法:FloodFill 算法

例题一 算法思路&#xff1a; 可以利⽤「深搜」或者「宽搜」&#xff0c;遍历到与该点相连的所有「像素相同的点」&#xff0c;然后将其修改成指定的像素即可。 全局变量&#xff1a; int dx[4] { 0,0,1,-1 }, dy[4] { 1,-1,0,0 }; int m, n; int precolor;//记录原先的颜色…

debian和ubuntu的核心系统和系统命令的区别

Debian和Ubuntu虽然有很深的渊源&#xff0c;都是基于Debian的发行版&#xff0c;但它们在核心系统和系统命令上还是有一些差别的。以下是一些主要的不同之处&#xff1a; 1. 发布周期&#xff1a; - Debian&#xff1a; Debian项目采用滚动发布模型&#xff0c;持续更新&a…

CCF区块链会议--Middleware 2024 截止5.24 附录用率

会议名称&#xff1a;Middleware CCF等级&#xff1a;CCF B类会议 类别&#xff1a;软件工程/系统软件/程序设计语言 录用率&#xff1a;2022年录用率38%&#xff08;8/21&#xff09; Topics of Interest The Middleware conference seeks original submissions of resear…

【Linux网络】Linux网络设置

如果你不会网络设置&#xff0c;就好比自己的拖鞋被硬控了&#xff0c;导致自己无法下床 目录 一、网络配置 1.1 主要配置网络的配置项 1.2 ifconfig——查看网卡配置 1.3 route——路由 1.4 hostname——主机名 1.5 ss——查看网络链接状态 1.6 scp——远程拷贝 1.7 …

39、Lua 中调用C函数(lua-5.2.3)

Lua可以调用C函数的能力将极大的提高Lua的可扩展性和可用性。 对于有些和操作系统相关的功能&#xff0c;或者是对效率要求较高的模块&#xff0c;我们完全可以通过C函数来实现&#xff0c;之后再通过Lua调用指定的C函数。 对于那些可被Lua调用的C函数而言&#xff0c;其接口…

游戏热更新进修——Lua编程

Lua编程 Lua是什么 Lua是一种轻量小巧的脚本语言&#xff0c;用标准C语言编写并以源代码形式开放&#xff0c;其设计目的是为了嵌入应用程序中&#xff0c;从而为应用程序提供灵活的拓展和定制功能 Lua可以方便的和其他进程进行集成(C,c#,java,) Lua应用场景 游戏开发独立应…

<网络> HTTP

目录 前言&#xff1a; 一、再谈协议 &#xff08;一&#xff09;认识URL &#xff08;二&#xff09;Encode 和 Decode 二、HTTP 协议 &#xff08;一&#xff09;协议格式 &#xff08;二&#xff09;见一见请求 &#xff08;三&#xff09;见一见响应 三、模拟实现响…

百度安全多篇议题入选Blackhat Asia以硬技术发现“芯”问题

Blackhat Asia 2024于4月中旬在新加坡隆重举行。此次大会聚集了业界最杰出的信息安全专业人士和研究者&#xff0c;为参会人员提供了安全领域最新的研究成果和发展趋势。在本次大会上&#xff0c;百度安全共有三篇技术议题被大会收录&#xff0c;主要围绕自动驾驶控制器安全、跨…

nvm的简介、安装、使用

一、nvm是什么&#xff1f; nvm是一个node的版本管理工具&#xff0c;可以简单操作node版本的切换、安装、查看。。。等等&#xff0c;与npm不同的是&#xff0c;npm是依赖包的管理工具。 二、nvm的安装。 2.1 nvm下载 安装包下载地址&#xff1a;https://github.com/coreyb…

共享单车(二):项目日志

stdin, stdout, stderr Linux系统下&#xff0c;当一个用户进程被创建时&#xff0c;与之对应的三个数据流&#xff08;stdin&#xff0c;stdout和stderr&#xff0c;即三个文件&#xff09;也会被创建。 stdin&#xff0c;标准输入文件&#xff0c;通常对应着终端的键盘。 s…

微前端qiankun

webcomponent 微前端&#xff1a;将产品的各个功能模块作为一个个独立的应用系统&#xff0c;然后将这些模块整合起来组装成完整的产品。 具体使用 https://qiankun.umijs.org/zh/guide/tutorial 注意&#xff1a;微应用需要配置打包格式和跨域&#xff1b; 打包格式&#xf…

【C语言 |预处理指令】预处理指令详解(包括编译与链接)

目录 一、编译与链接 1.翻译环境 -预处理 -编译 -汇编 -链接 2.执行环境 二、预定义符号 三、#define定义常量 四、#define定义宏 五、带有副作用的宏参数 六、宏替换的规则 七、 宏函数的对比 八、#和## 1.#运算符 2.##运算符 九、命名约定 十、#undef 十一、 命…

IDEA本地将镜像推送到coding制品仓库

创建制品仓库 假设仓库名称为docker 在IDEA 添加Docker 注册表 IDEA必须先安装docker插件 地址 用户名和密码就是coding的登录名和密码服务器 最好本地安装docker桌面版&#xff0c;更容易操作 测试连接成功 推送镜像到coding的docker制品仓库 选中某个镜像 鼠标右键 注册表…

四.RocketMQ的几种消息发送方式应用

RocketMQ的几种消息发送方式应用 一&#xff1a;普通消息1&#xff09;发送同步消息2&#xff09;发送异步消息3&#xff09;单向发送消息4&#xff09;消费消息-负载均衡模式5&#xff09;消费消息-广播模式 二&#xff1a;顺序消息1.顺序消息指的是:严格按照消息的发送顺序进…

服务器数据恢复—ESXi无法识别数据存储和VMFS文件系统如何恢复数据?

服务器数据恢复环境&#xff1a; 一台某品牌服务器&#xff0c;通过FreeNAS来做iSCSI&#xff0c;然后使用两台同品牌服务器做ESXi虚拟化系统。 FreeNAS层为UFS2文件系统&#xff0c;使用整个存储建一个稀疏模式的文件&#xff0c;挂载到ESXi虚拟化系统。ESXi虚拟化系统中有3台…

react实现时钟翻牌效果

需求&#xff1a;随着数字的变动要求有时钟翻动动效 问题&#xff1a;只在加载时有动效 解决方案&#xff1a;通过判断数字改变&#xff08;这里通过新旧数值变动来判断&#xff0c;不贴代码啦&#xff09;&#xff0c;每次变动的时候手动把animationIterationCount设置为inf…