浅谈Java内省

作者:京东物流 王国泰

一、什么是内省

  • 讲内省,不得不说Java Bean,Bean在Java中是一种特殊的类,主要用于装载数据,数据会被存储在类的私有属性中,通常具有无参构造函数、可序列化、以及通过getter和setter方法来访问属性。内省是Java Beans规范的一部分,使用java.beans包中的类来实现,最常用的类是Introspector。通过内省,你可以获取一个Java Bean的属性描述符(PropertyDescriptor)和方法描述符(MethodDescriptor)

二、内省常用API

1、相关类

2、Introspector

2.1 核心功能

  • 用于获取Bean的整体信息,包括属性描述符、方法描述符和事件描述符等

2.2 核心方法

  • getBeanInfo
ini 复制代码
BeanInfo beanInfo = Introspector.getBeanInfo(Vehicle.class);

3、BeanInfo

3.1 核心功能

  • 用于提供有关Bean的元数据,通常用于描述Bean的属性、事件和方法

3.2 核心方法

  • getPropertyDescriptors
ini 复制代码
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
  • getMethodDescriptors
ini 复制代码
MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();
  • getEventSetDescriptors
ini 复制代码
EventSetDescriptor[] eventSetDescriptors = beanInfo.getEventSetDescriptors();

4、PropertyDescriptor

4.1 核心功能

  • 用于描述Bean的属性,提供了对属性的详细描述,包括属性的名称、类型、读方法getter、写方法setter等

4.2 核心方法

  • getName
ini 复制代码
PropertyDescriptor namePD = new PropertyDescriptor("name", Vehicle.class);
String name = namePD.getName();
  • getReadMethod
ini 复制代码
PropertyDescriptor namePD = new PropertyDescriptor("name", Vehicle.class);
Method getter = namePD.getReadMethod();

String methodName = getter.getName();
String vehicleName = (String) getter.invoke(new Vehicle());
  • getWriteMethod
ini 复制代码
PropertyDescriptor namePD = new PropertyDescriptor("name", Vehicle.class);
Method setter = namePD.getWriteMethod();

String methodName = setter.getName();
setter.invoke(new Vehicle(), "JD0001");

5、MethodDescriptor

5.1 核心功能

  • 用于描述一个方法的属性,提供了对方法的详细描述,包括方法的名称、参数类型、返回类型等

5.2 核心方法

  • getName
ini 复制代码
MethodDescriptor methodDescriptor = new MethodDescriptor(Vehicle.class.getMethod("setName", String.class));
String name = methodDescriptor.getName();
  • getMethod
arduino 复制代码
MethodDescriptor methodDescriptor = new MethodDescriptor(Vehicle.class.getMethod("setName", String.class));
Method method = methodDescriptor.getMethod();
method.invoke(new Vehicle(), "JD0001");

6、EventSetDescriptor

6.1 核心功能

  • 用于描述一个Bean能够触发的一组事件,提供了有关事件监听器类型、添加和移除监听器的方法以及事件通知方法的信息

6.2 核心方法

  • 不常用

三、内省常见使用场景

1、依赖注入

  • Spring使用内省来分析类的构造函数、字段和方法,并自动注入依赖对象,可参考BeanWrapperImpl,部分源码如下:
scss 复制代码
@Override
public PropertyDescriptor[] getPropertyDescriptors() {
  return getCachedIntrospectionResults().getPropertyDescriptors();
}

2、对象拷贝

  • Spring BeanUtils使用内省来复制对象的属性,可参考BeanUtils,部分源码如下:
scss 复制代码
public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws BeansException {
  return CachedIntrospectionResults.forClass(clazz).getPropertyDescriptors();
}

3、开发工具和IDE

  • 开发工具和集成开发环境(IDE,如IntelliJ IDEA)使用内省来提供代码补全、重构、调试等功能

四、内省优缺点

1、优点

  • 灵活性和可扩展性:允许在运行时动态地获取和操作对象的属性和方法
  • 简化开发工作:支持框架和工具的开发,能够自动处理对象的属性和方法

2、缺点

  • 性能开销:比直接调用方法或访问字段要慢,而且不当使用可能会导致内存泄漏或增加GC压力
  • 访问安全:绕过Java的访问控制机制,访问私有字段和方法,可能会带来安全隐患,特别是在处理敏感数据时
  • 类型安全:通常是基于字符串名称进行的(如方法名、属性名),在编译时无法检查其正确性,容易导致运行时错误
  • 可读性和可维护性:代码可读性差,增加调试难度

五、内省与反射的区别

1、用途

  • 内省主要用于Java Bean的属性操作,适合于标准化的Bean操作
  • 反射则是更通用的机制,可以操作类的所有成员,包括私有成员

2、实现

  • 内省是基于Java Beans规范的,使用java.beans包
  • 反射是Java语言的核心特性,使用java.lang.reflect包

3、性能

  • 内省通常比反射快,主要原因是内省使用了缓存机制,减少了权限检查,并且在设计上针对特定场景进行了优化

相关文献

  • JavaBeans API Specification:docs.oracle.com/javase/8/do...
  • 《Java编程思想》(Thinking in Java) - Bruce Eckel
  • 《Java核心技术 卷 I》(Core Java Volume I) - Cay S. Horstmann, Gary Cornell
  • 《Java反射机制详解》(Java Reflection in Action) - Ira R. Forman, Nate Forman
相关推荐
文心快码BaiduComate20 分钟前
Comate 搭载GLM-5.2:百万上下文,稳定支撑长程任务
前端·程序员·开源
程序员cxuan1 小时前
分享一下我最近常用的 10 个 Codex 小技巧。
人工智能·后端·程序员
Moonbit1 小时前
MoonBit ×CCF开源创新大赛 倒计时24天!快来提交你的作品
程序员·编程语言
zzzzzz3102 小时前
假如我是掘金管理员,我先给评论区装个'代码审查'系统
python·程序员·机器人
demo007x16 小时前
Docling 文档转换以及技术架构分析
前端·后端·程序员
保持当下17 小时前
分享一些程序员很棘手但是却又简单的工具
程序员·免费·js·工具
Hilaku20 小时前
AI 写代码越快,为什么 Code Review 越不能省?
前端·javascript·程序员
程序员cxuan20 小时前
LobsterAI 快把职业门槛打没了
人工智能·程序员
Coffeeee1 天前
Codachi — 藏在 Claude Code 状态栏里的电子宠物
人工智能·程序员·claude