java-内省机制
内省是指程序运行时检查对象类型的能力。在 Java 中,内省机制是一种用于处理符合 JavaBean 规范的类的方法。它提供了一套 API,允许我们通过程序化的方式访问和操作类的属性、方法及事件。通过这种方式,我们可以在不知道具体实现细节的情况下,动态地访问或修改对象的状态
内省和反射
- 反射是一种更为通用的技术,指程序在运行时通过检查或“自检”其结构,动态修改自身行为的能力。通过反射,我们可以动态地加载类、创建对象实例、调用方法以及访问字段等,并且反射是可以应用于任何类的,无论该类是否遵循了 JavaBean 规范
- 内省其实是基于反射实现的,只是提供了更高层次的抽象,它更专注于对 JavaBean 的操作,使得操作 JavaBean 更加方便高效。例如,当我们想要获取某个类的所有公共字段时,可以使用反射直接获取
Field
对象数组;但如果操作的目标符合 JavaBean 规范,则应该优先考虑使用内省机制
什么是JavaBean
JavaBean 是指符合特定规范的 Java 类,主要用于封装数据。成为一个 JavaBean 需要满足以下这几个条件:
- 无参构造方法:必须有一个无参构造方法,确保可以通过默认构造器创建实例。
- 私有化属性:所有属性须使用
private
访问修饰符封装,防止外部随意更改类的内部状态。- 提供公共的 getter 和 setter 方法:为每个属性定义相应的
public
读写方法,并遵循命名约定(如getName()
和setName(String name)
)。- 序列化支持:实现
Serializable
接口,以保证对象能够序列化为字节流便于存储或者网络传输。
核心组件
Java 内省机制主要依赖于 java.beans
包下的几个关键类和接口
-
Introspector 类:内省机制的核心类,提供了静态方法
getBeanInfo(Class<?> beanClass)
来获取给定类型的 JavaBean 信息。该方法返回一个BeanInfo
对象,对象中包含了关于此 JavaBean 的全面描述,包括所有属性、方法和事件等信息。 -
BeanInfo 接口:JavaBean 信息的顶层抽象,定义了如何描述一个 JavaBean 的行为,用于提供 JavaBean 的元数据。通过
BeanInfo
,我们可以获取 Bean 的属性描述符(PropertyDescriptor[] getPropertyDescriptors()
)、方法描述符(MethodDescriptor[] getMethodDescriptors()
)以及其他相关信息。 -
PropertyDescriptor 类:对于 JavaBean 的每一个属性,都会有一个对应的
PropertyDescriptor
实例。该类不仅封装了属性的基本信息(如名称、类型),还提供了对 getter 和 setter 方法的访问途径。获取到PropertyDescriptor
实例后,就可以实现 JavaBean 的属性值读写了。
DEMO
UserDTO user = new UserDTO();
user.setName("zhangsan");
//查看所有属性和值
BeanInfo beanInfo = Introspector.getBeanInfo(UserDTO.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
if ("class".equals(propertyDescriptor.getName()))
continue;
String name = propertyDescriptor.getName();
Object value = propertyDescriptor.getReadMethod().invoke(user);
System.out.println(name+":"+value);
}
//修改指定属性的值 注意:对set方法的名称和结构有强要求,如使用Lombok的@Accessors会报错
PropertyDescriptor pd = new PropertyDescriptor("name",UserDTO.class);
Method writeMethod = pd.getWriteMethod();
writeMethod.invoke(user,"lisi");
//查看指定属性的值
Method readMethod = pd.getReadMethod();
Object newValue = readMethod.invoke(user);
System.out.println(newValue);