本文主要是介绍反射 - - - - - - - - 内省【精细】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1、概念
Java内省机制(Introspection)是一种访问Java Bean属性的方式,它允许程序在运行时获取和设置Java对象的属性。通过内省机制,程序可以在运行时获取对象的属性名、类型和值,并动态地设置对象的属性值。内省机制为Java反射机制的一个重要应用,使得Java Bean对象可以更加灵活地被访问和处理。
2、Java内省的作用
- 动态访问Java对象的属性和方法:Java内省可以在运行时动态获取Java对象的属性和方法信息,并访问其属性值和调用其方法。
- 避免硬编码对象的属性和方法名称:Java内省可以通过反射机制避免硬编码对象的属性和方法名称,从而使程序更加灵活和可扩展。
- 提高代码的可读性和可维护性:Java内省可以使代码更加简洁和易读,同时也方便了代码的维护和修改。
- 支持动态代理和AOP编程:Java内省可以支持动态代理和AOP编程,从而实现更加灵活和可扩展的编程。
3、Java内省的实现机制
Java内省的实现机制基于Java的反射机制。在Java中,每个类都有一个Class对象,可以通过这个Class对象获取类的各种信息,包括类的名称、构造方法、属性和方法等。Java内省通过分析Class对象来获取Java对象的属性和方法信息,并通过反射机制访问其属性值和调用其方法。
二、Java内省的核心类
Java内省的核心类包括
Introspector
、BeanInfo
、PropertyDescriptor
、MethodDescriptor
和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、优点
- 方便:Java内省提供了一种便捷的方式,可以通过BeanInfo、PropertyDescriptor和MethodDescriptor等类来动态地访问Java对象的属性和方法,而不需要手动编写大量的反射代码。
- 易用:Java内省提供了一组简单易用的API,使得开发人员可以方便地读取、设置和复制Java对象的属性。
- 高效:相比于纯反射机制,Java内省的性能更高,因为它缓存了Java类的属性和方法信息,并且避免了多次调用反射机制。
- 安全:Java内省在访问Java对象的属性和方法时,会对访问权限进行检查,确保访问的属性和方法是可访问的。
2、缺点
- 局限性:Java内省只能访问JavaBean中的属性和方法,无法访问其他类型的对象。
- 可读性差:由于Java内省需要使用PropertyDescriptor和MethodDescriptor等类来访问JavaBean中的属性和方法,因此代码可读性不如直接使用JavaBean的属性和方法。
- 不够灵活:由于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的依赖注入和动态代理等功能。
这篇关于反射 - - - - - - - - 内省【精细】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!