文章多参考 ,搬运工上线 https://www.cnblogs.com/jiading/articles/12486921.html
一、内省机制概述
Java语言对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName,setName来得到其值或者设置新的值。通过getName/setName来访问name属性,这就是默认的规则。Java中提供了一套API用来访问某个属性的getter/setter方法,通过这些API可以使你不需要了解这个规则(但你最好还是要搞清楚),这些API存放于包java.beans中。
一般的做法是通过类Introspector来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法。
内省在wiki上的解释:
在计算机科学中,内省是指计算机程序在运行时(Run time)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查。
不应该将内省和反射混淆。相对于内省,反射更进一步,是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。
https://zh.wikipedia.org/zh-hans/%E5%86%85%E7%9C%81_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)
Java 中的反射机制是通过名称得到类的方法和对象的成份,对于一切 Java 类都是适用的,但是有时候使用起来比较麻烦。而 JavaBean 是一种特殊的 Java 类,遵守 JavaBean 的规范,即所有的成员都是私有成员,且每个成员都有公开的读取和设定的方法(getter 和 setter),且这些方法都遵守命名的规范。就是因为 JavaBean 有这些的特性,sun 推出了一种专门对 JavaBean 成员进行访问的技术,方便对其的访问,就是内省技术。
即:通过内省机制(自省机制)可以获取和操作 JavaBean 中的成员信息(方法,事件和属性)。
JavaBean 规范:
什么是 JavaBean:符合某些设计规范的类。使用 JavaBean,可避免代码重复问题,起到功能重复使用。
类必须使用public修饰
必须保证有公共无参数的构造器
包含属性(property)的操作手段(getter/setter方法)
JavaBean包含的成员:method方法、event事件或property属性
1、内省和反射有什么区别?
反射 (Reflect) 是在运行状态把 Java 类中的各种成分映射成相应的 Java 类,可以动态的获取所有的属性以及动态调用任意一个方法,强调的是运行状态。
内省 (IntroSpector) 是 Java 语言对 Bean 类属性、事件的一种缺省处理方法。内省机制是通过反射来实现的
2、内省机制的作用
用于查看和操作 JavaBean 中的属性:
-
l获取 JavaBean 中的每一个属性名 / 属性类型
-
l通过 getter 方法获取属性值,通过 setter 方法给属性设置值
3、内省机制中使用到的核心几个类,列举几个常用方法,具体查看 API
1.java.beans.Introspector 类
Introspector 相当于一个工具类,提供了一种标准的工具来了解目标 JavaBean 支持的属性,事件和方法,即一系列取得 Bean 信息的方法。
getBeanInfo(Class beanClass)
内省 Java Bean 并了解其所有属性,暴露的方法和事件。
2.java.beans.BeanInfo 接口
beanInfo 接口是对一个 Bean 的描述,可以通过它取得 Bean 内部的信息。
getEventSetDescriptors()
返回 bean 定义此 bean 触发的事件类型的事件描述符。
3.java.beans.PropertyDescriptor 类
PropertyDescriptor 类是对一个 Bean 属性的描述,它提供了一系列对 Bean 属性进行操作的方法。
getPropertyType()
返回属性的 Java 类型信息。
java.beans.FeatureDescriptor 类是 PropertyDescriptor,EventSetDescriptor 和 MethodDescriptor 等的常见基类 (父类)。
它支持一些可以为任何内省描述符设置和检索的常见信息
getName()
获取此功能的编程名称。
二、demo
public class User {
private Long id;
private String username;
private Integer age;
private Long account;
public User() {
}
getter,setter,toString 方法
}
1.通过内省机制获取 JavaBean 属性值和属性设值
@Test
public void testIntrospector() throws Exception {
User user = User.class.newInstance();
user.setId(111L);
// 获取JavaBean的描述对象BeanInfo
//BeanInfo beanInfo = Introspector.getBeanInfo(User.class); // 包含父类的,比如:getClass()
BeanInfo beanInfo = Introspector.getBeanInfo(User.class, Object.class); // 不包含父类的
// 获取JavaBean中所有属性的描述器对象PropertyDescriptor
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
// 获取当前属性的名称
String name = pd.getName();
if("id".equals(name)){
// 调用getter方法,获取属性值
Object value = pd.getReadMethod().invoke(user);
System.out.println(value); // 111
}
if("username".equals(name)){
// 获取当前属性的数据类型
Class propertyType = pd.getPropertyType();
System.out.println(propertyType); //class java.lang.String
// 调用setter方法,设置属性值
pd.getWriteMethod().invoke(user,"赵云");
}
if("age".equals(name)){
pd.getWriteMethod().invoke(user,17);
}
}
System.out.println(user); //User{id=null, username='赵云', age=17, account=null}
}
2、JavaBean 与 Map 之间的相互转换
//JavaBean对象转Map
public Mapbean2map(Object bean) throws Exception {
Map map = new HashMap<>();
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
String name = pd.getName();
Object value = pd.getReadMethod().invoke(bean);
map.put(name,value);
}
return map;
}
//Map转JavaBean对象
public T map2bean(Mapmap, Classclazz) throws Exception {
T t = clazz.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
Object value = map.get(pd.getName());
pd.getWriteMethod().invoke(t,value);
}
return t;
}
@Test
public void testChange() throws Exception {
User user = new User();
user.setUsername("赵云");
user.setAge(17);
Map Object> map = bean2map(user);
System.out.println(map); // {id=null, account=null, age=17, username=赵云}
map.put("account",1000L);
Class userClass = User.class;
User user1 = map2bean(map, userClass);
System.out.println(user1);// User{id=null, username='赵云', age=17, account=1000}
}
三、总结:
-
l使用内省机制对 JavaBean 属性进行操作还是很复杂的,一些第三方组织封装了某些工具类来方便开发者使用,如:org.apache.commons.beanutils.BeanUtils 是 apache 封装的工具类,用来解决使用内省机制繁琐的问题,包含了挺多方法。使用时要导入两个包:commons-beanutils-xx.jar 和 commons-logging-xx.jar。
-
l 将 Java 的反射以及内省应用到程序设计中去可以大大的提供程序的智能化和可扩展性。有很多项目或者框架都是采取这两种技术来实现其核心功能。比如 Struts2,SpringMVC。这些框架只要在. action 中,或者 controller 方法的形参处,引入 JavaBean 就可以实例化这个 JavaBean 的值,并且可以获得表单提交的数据,那么它究竟是怎么得到的呢? 其实就是 request.getParameterMap() 获取得到表单提交来的所有键值对,只不过框架内部封装了,然后框架内部利用内省,将数据封装到 JavaBean 中。Spring 中 BeanWrapper 基于 Java 的内省机制实现了对属性的赋值工作,具体详情参考https://xiaomi-info.github.io/2020/03/16/java-beans-introspection/
-
lJava 的反射以及内省机制重点掌握,查阅框架源码时多加留意,理解其中的设计重构封装等思想
原文始发于微信公众号(赛博少女):Java 内省机制
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论