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

2024-04-25 09:04
文章标签 反射 精细 内省

本文主要是介绍反射 - - - - - - - - 内省【精细】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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.chinasem.cn/article/934241

相关文章

【反射知识点详解】

Java中的反射(Reflection)是一个非常强大的机制,它允许程序在运行时检查或修改类的行为。这种能力主要通过java.lang.reflect包中的类和接口来实现。 通过反射,Java程序可以动态地创建对象、调用方法、访问字段,以及获取类的各种信息(如构造器、方法、字段等)。 反射的用途 反射主要用于以下几种情况: 动态创建对象:通过类的Class对象动态地创建其实例。访问类的字段

Go 在orm中使用反射

作为静态语言,golang 稍显笨拙,还好 go 的标准包reflect(反射)包弥补了这点不足,它提供了一系列强大的 API,能够根据执行过程中对象的类型来改变程序控制流。本文将通过设计并实现一个简易的 mysql orm 来学习它,要求读者了解mysql基本知识,并且跟我一样至少已经接触 golang 两到三个月。 orm 这个概念相信同学们都非常熟悉,尤其是写过rails的同学,对acti

类型信息:反射-Class

在说反射前提一个概念:RTTI(在运行时,识别一个对象的类型) public class Shapes {public static void main(String[] args) {List<Shape> shapes = Arrays.asList(new Circle(), new Square(), new Triangle());for (Shape shape : shapes

单例模式以及反射对单例模式的破坏及防御

单例模式(Singleton Pattern)是一种确保类在应用程序生命周期内只存在一个实例的设计模式。它不仅提供了全局访问点,还能节省内存、控制实例的生命周期。但常见的单例模式实现方式如饿汉式、懒汉式、双重校验锁、静态内部类等,虽然设计良好,但都容易被 Java 的反射机制所破坏。本文将介绍这些单例实现方式的优缺点、反射如何破坏它们的唯一性,以及如何防御这种破坏。 1. 单例模式的常见实现

servlet用反射代替if..else

String methodName = request.getParameter("method"); Method method = this.getClass().getDeclaredMethod(methodName,HttpServletRequest.class, HttpServletResponse.class); method.invoke(this, request, re

Redis缓存 自定义注解+aspect+反射技术实现

最近再给云随笔后台增加redis模块,突然发现spring-boot-starter-data-redis模块很不人性化,实现不了通用的方式,(当然,你也可以自己写个通用的CacheUtil来实现通用的方式),但由于本人非常的爱装逼,就在这里不讲解那种傻瓜式操作了,这里只讲干货,干到你不可置信的干货). 例如:这里我使用了它其中的RedisTemplate ,发现存到redis中后,数据

JAVA反射使用父类的非public方法(getMethods()和getDeclaredMethods()区别)

getMethods()和getDeclaredMethods()区别 虽然是老生常谈了,但是还是要先说一下两者的区别。 getMethods():能够获取类的所有public方法,包括自身定义的以及从父类继承的。 getDeclaredMethods():能够获取类本身的所有方法,包括private方法,实现的接口方法,但是不能获取从父类继承的非public方法。 因此getDeclaredM

Java反射机制讲解

Java反射机制详解 Java反射机制是Java语言的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。这意味着可以动态地创建对象、调用方法、访问字段等。 1. 反射的基本概念 反射主要是指运行时能够“反观”自己,并且可以直接操作对象的结构(类、字段、方法等)。Java反射的主要功能包括: 获取Class对象创建对象实例获取和设置字段值调用方法获取构造器

反射: 获取变量类型

更高级的编程语言,提供反射、解释机制,获取对象类型非常方便,因为运行时保存有对象的全部信息,也包括类型,而对于编译型语言而言,变量类型要靠编译期或构造/依赖类型某个存储类型的结构。 不同语言的反射 C++ typeid编译器编译时可以确定某些无多态的变量对象类型,无需额外结构辅助。对于有多态行为的类对象,编译器利用vtable内指向对应类型的type_info, 运行期可通过vtable获

mybatis特殊符号处理,mybatis一级二级缓存,java反射机制

mybatis特殊符号处理 在 mybatis 中的 xml 文件中,存在一些特殊的符号,比如:<、>、"、&、<>等,正常书写 mybatis 会报错,需要对这些符号进行转义。具体转义如下所示: 特殊字符 转义字符 <  &lt; >  &gt; "  &quot; ’  &apos; &  &amp; 除此之外,还可以使用印射文件特殊处理,因为sql印射文件时xml类型文件,在转义上面有些