1.  什么是内省?

内省(Introspector)是Java语言对JavaBean类属性、事件的处理方法。

例如类User中有属性name,那么必定有getName,setName方法,我们可以通过他们来获取或者设置值,这是常规操作。

Java提供了一套API来访问某个属性的getter/setter方法,这些API存放在java.beans中。

在计算机科学中,内省是指计算机程序在运行时(Run time)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查。

不应该将内省和反射混淆。相对于内省,反射更进一步,是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。

内省和反射的区别:

反射是在运行状态把Java类中的各种成分映射成相应的Java类,可以动态的获取所有的属性以及动态调用任意一个方法,强调的是运行状态。

内省机制是通过反射来实现的,BeanInfo用来暴露一个bean的属性、方法和事件,以后我们就可以操纵该JavaBean的属性。

我自己的理解是:

内省更多的用在获取属性以及属性的的getter、setter方法,进行一些其他的操作。

反射更多的用在反射创建对象以及调用方法等操作。

2.  内省类库简介

比如User类:

packagecn.qlq;public classUser {private intage;privateString name;privateAddress address;private booleandeleted;public intgetAge() {returnage;

}public void setAge(intage) {this.age =age;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}publicAddress getAddress() {returnaddress;

}public voidsetAddress(Address address) {this.address =address;

}public booleanisDeleted() {returndeleted;

}public void setDeleted(booleandeleted) {this.deleted =deleted;

}

}classAddress {privateString province;privateString city;publicString getProvince() {returnprovince;

}public voidsetProvince(String province) {this.province =province;

}publicString getCity() {returncity;

}public voidsetCity(String city) {this.city =city;

}

}

主要涉及的类库如下:

(1)Introspector类,可以获取BeanInfo类,常见的使用方法如下:(重要)

BeanInfo beanInfo =Introspector.getBeanInfo(user.getClass());//第二个参数代表停止的类,也就是如果有继承关系不获取第二个参数及其父类的信息

BeanInfo beanInfo2 = Introspector.getBeanInfo(user.getClass(), Object.class);

(2)BeanInfo类:通过上面的内省类获得 (重要)

BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass(), Object.class);

作用1:获取BeanDescriptor一个全局的类描述信息

//获取BeanDescriptor-一个全局的类描述信息

BeanDescriptor beanDescriptor =beanInfo.getBeanDescriptor();

System.out.println(beanDescriptor);

作用2:获取所有的PropertyDescriptor属性描述器(如果获取BeanInfo的时候第二个参数没传会获取从Object继承的信息)

private static void testBeanInfo2(User user) throwsException {

BeanInfo beanInfo= Introspector.getBeanInfo(user.getClass(), Object.class);//获取PropertyDescriptor描述器

PropertyDescriptor[] propertyDescriptors =beanInfo.getPropertyDescriptors();for(PropertyDescriptor propertyDescriptor : propertyDescriptors) {//获取属性类型

Class> propertyType =propertyDescriptor.getPropertyType();//获取属性名称

String name =propertyDescriptor.getName();//获取属性的读方法,getXXX

Method readMethod =propertyDescriptor.getReadMethod();//获取属性的写方法,setXXX

Method writeMethod =propertyDescriptor.getWriteMethod();

System.out.println(name);

System.out.println(propertyType);

System.out.println(readMethod.getName());

System.out.println(writeMethod.getName());

System.out.println("==============");

}

}

结果:

address

class cn.qlq.Address

getAddress

setAddress

==============

age

int

getAge

setAge

==============

deleted

boolean

isDeleted

setDeleted

==============

name

class java.lang.String

getName

setName

==============

作用3: 获取MethodDescriptor描述器(如果获取BeanInfo的时候第二个参数没传会获取从Object继承的方法)

BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass(), Object.class);//获取MethodDescriptor描述器

MethodDescriptor[] methodDescriptors =beanInfo.getMethodDescriptors();for(MethodDescriptor methodDescriptor : methodDescriptors) {

Method method=methodDescriptor.getMethod();

System.out.println(method);

}

结果:

public java.lang.String cn.qlq.User.getName()

public void cn.qlq.User.setAge(int)

public void cn.qlq.User.setName(java.lang.String)

public int cn.qlq.User.getAge()

public boolean cn.qlq.User.isDeleted()

public cn.qlq.Address cn.qlq.User.getAddress()

public void cn.qlq.User.setAddress(cn.qlq.Address)

public void cn.qlq.User.setDeleted(boolean)

作用4:获取EventSetDescriptor(这个不常用)

BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass(), Object.class);//获取EventSetDescriptor描述器

EventSetDescriptor[] eventSetDescriptors =beanInfo.getEventSetDescriptors();for(EventSetDescriptor eventSetDescriptor : eventSetDescriptors) {

System.out.println(eventSetDescriptor);

}

(3)BeanDescriptor  一个全局的Bean描述信息,一般没啥用

BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass(), Object.class);//获取BeanDescriptor-一个全局的类描述信息

BeanDescriptor beanDescriptor =beanInfo.getBeanDescriptor();

System.out.println(beanDescriptor);

(4)PropertyDescriptor  属性描述器,可以获取到属性名称、属性的get方法以及set方法,进而做到修改方法。

其获取方式可以通过BeanInfo获取,也可以通过直接new的方式获取。

方式一:

BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass(), Object.class);//获取PropertyDescriptor描述器

PropertyDescriptor[] propertyDescriptors =beanInfo.getPropertyDescriptors();for(PropertyDescriptor propertyDescriptor : propertyDescriptors) {//获取属性类型

Class> propertyType =propertyDescriptor.getPropertyType();//获取属性名称

String name =propertyDescriptor.getName();//获取属性的读方法,getXXX

Method readMethod =propertyDescriptor.getReadMethod();//获取属性的写方法,setXXX

Method writeMethod =propertyDescriptor.getWriteMethod();

System.out.println(name);

System.out.println(propertyType);

System.out.println(readMethod.getName());

System.out.println(writeMethod.getName());

System.out.println("==============");

}

方式二:通过直接new的方式

User user = newUser();

user.setName("zhangsan");

PropertyDescriptor propertyDescriptor= new PropertyDescriptor("name", User.class);//获取getter方法读取属性

Method readMethod =propertyDescriptor.getReadMethod();

Object invoke=readMethod.invoke(user);

System.out.println(invoke);//获取setter方法修改属性

Method writeMethod =propertyDescriptor.getWriteMethod();

writeMethod.invoke(user,"lisi");

System.out.println(user.getName());

结果:

zhangsan

lisi

如果属性不存在会报错如下:

Exception in thread "main" java.beans.IntrospectionException: Method not found: isNamess

at java.beans.PropertyDescriptor.(PropertyDescriptor.java:107)

at java.beans.PropertyDescriptor.(PropertyDescriptor.java:71)

at cn.qlq.Client.main(Client.java:14)

(5)  MethodDescriptor 方法描述器,可以获取方法的名称、Method等信息

其获取方式可以通过BeanInfo获取

BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass(), Object.class);//获取MethodDescriptor描述器

MethodDescriptor[] methodDescriptors =beanInfo.getMethodDescriptors();for(MethodDescriptor methodDescriptor : methodDescriptors) {

System.out.println(methodDescriptor);

Method method=methodDescriptor.getMethod();

}

3.  内省的应用

采用内省实现的JavaBean转Map和List转List、Map转Bean、Maps转Beans、实现将1个bean的属性赋值给另1个bean(属性拷贝)

packagecn.qs.utils;importjava.beans.BeanInfo;importjava.beans.Introspector;importjava.beans.PropertyDescriptor;importjava.lang.reflect.Method;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.List;importjava.util.Map;importorg.apache.commons.lang3.ArrayUtils;public classBeanUtils {/*** 内省进行数据转换-javaBean转map

*

*@paramobj

* 需要转换的bean

*@return转换完成的map

*@throwsException*/

public static Map beanToMap(T obj, boolean putIfNull) throwsException {

Map map = new HashMap<>();//获取javaBean的BeanInfo对象

BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass(), Object.class);//获取属性描述器

PropertyDescriptor[] propertyDescriptors =beanInfo.getPropertyDescriptors();for(PropertyDescriptor propertyDescriptor : propertyDescriptors) {//获取属性名

String key =propertyDescriptor.getName();//获取该属性的值

Method readMethod =propertyDescriptor.getReadMethod();//通过反射来调用javaBean定义的getName()方法

Object value =readMethod.invoke(obj);if (value == null && !putIfNull) {continue;

}

map.put(key, value);

}returnmap;

}public static List> beansToMaps(List objs, boolean putIfNull) throwsException {return beansToMaps(objs, putIfNull, false);

}public static List> beansToMaps(List objs, boolean putIfNull, booleanaddIndex)throwsException {

List> result = new ArrayList<>();

Map beanToMap = null;int index = 0;for(Object obj : objs) {

beanToMap=beanToMap(obj, putIfNull);if(addIndex) {

beanToMap.put("index", ++index);

}

result.add(beanToMap);

}returnresult;

}/*** Map转bean

*

*@parammap

* map

*@paramclz

* 被转换的类字节码对象

*@return*@throwsException*/

public static T map2Bean(Map map, Class clz) throwsException {//new 出一个对象

T obj =clz.newInstance();//获取person类的BeanInfo对象

BeanInfo beanInfo = Introspector.getBeanInfo(clz, Object.class);//获取属性描述器

PropertyDescriptor[] propertyDescriptors =beanInfo.getPropertyDescriptors();for(PropertyDescriptor propertyDescriptor : propertyDescriptors) {//获取属性名

String key =propertyDescriptor.getName();

Object value=map.get(key);//通过反射来调用Person的定义的setName()方法

Method writeMethod =propertyDescriptor.getWriteMethod();

writeMethod.invoke(obj, value);

}returnobj;

}public static List maps2Beans(List> maps, Class clz) throwsException {

List result = new ArrayList<>();for (Mapmap : maps) {

result.add(map2Bean(map, clz));

}returnresult;

}/*** 复制origin的值到dest上

*

*@paramdest

* 目标对象

*@paramorigin

* 元对象

*@paramsetNull

* 如果源对象属性为null是否拷贝

*@paramexcludeFieldNames

* 排除的属性*/

public static void copyProperties(T dest, T origin, booleansetNull, String[] excludeFieldNames) {try{//获取person类的BeanInfo对象

BeanInfo destBeanInfo = Introspector.getBeanInfo(dest.getClass(), Object.class);//获取目标属性描述器

PropertyDescriptor[] destBeanInfoPropertyDescriptors =destBeanInfo.getPropertyDescriptors();for(PropertyDescriptor propertyDescriptor : destBeanInfoPropertyDescriptors) {//获取属性名

String key =propertyDescriptor.getName();if(ArrayUtils.contains(excludeFieldNames, key)) {continue;

}//获取该属性的值

Method readMethod =propertyDescriptor.getReadMethod();//如果源对象没有对应属性就跳过

Object srcValue = null;try{

srcValue=readMethod.invoke(origin);

}catch(Exception ignored) {//ignored

continue;

}//如果源对象的值null且null不设置的时候跳过

if (srcValue == null && !setNull) {continue;

}//获取setter方法修改属性

Method writeMethod =propertyDescriptor.getWriteMethod();

writeMethod.invoke(dest, srcValue);

}

}catch(Exception ignored) {//ignored

}

}public static voidcopyProperties(T dest, T origin) {

copyProperties(dest, origin,false, null);

}

}

总结:

如果通过BeanInfo操作属性的话,一般需要过滤掉Object继承的东西,也就是获取BeanInfo的时候如下:

BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass(), Object.class);

java内省有什么作用_Java内省相关推荐

  1. java内省和反射机制_Java内省和反射机制三步曲之 - 内省

    经过多方面的资料搜集整理,写下了这篇文章,本文主要讲解java的反射和内省机制,希望对大家有点帮助,也希望大家提出不同的看法! 1).内省(Introspector)是 Java 语言对 Bean 类 ...

  2. java类与对象作用_Java类与对象

    ●类和对象的关系: 一:类是对同一类事物(对象)的抽象,对象实际存在的该类的各种实体. 二:面向对编程的核心:找合适的对象来做合适的事. 三:Java中找到对象: 1):sun自己定义好的类,必须知道 ...

  3. java 代码块的作用_Java核心(三):代码块的作用

    Java中用{ }括起来的代码段就是代码块,他分为如下几种类型 位置 作用 局部代码块 在方法当中使用,作用是控制变量的生命周期. 局部代码块的变量,只能在代码块内部使用,在执行结束后会被Java回收 ...

  4. java 中gui的作用_java学习中最应该注意的Java GUI用户界面以何为基础

    java中的GUI编程(Graphic User Interface,图形用户接口),是在它的笼统窗(Abstract Window Toolkit,AWT)上完成的,java.awt是AWT的东西类 ...

  5. java volatile关键字的作用_java volatile关键字作用及使用场景详解

    1. volatile关键字的作用:保证了变量的可见性(visibility).被volatile关键字修饰的变量,如果值发生了变更,其他线程立马可见,避免出现脏读的现象.如以下代码片段,isShut ...

  6. java中flush函数作用_Java语言中flush()函数作用及使用方法详解

    最近在学习io流,发现每次都会出现flush()函数,查了一下其作用,起作用主要如下 //------–flush()的作用--------– 笼统且错误的回答: 缓冲区中的数据保存直到缓冲区满后才写 ...

  7. java 注解处理器的作用_Java注解处理器

    Java中的注解(Annotation)是一个很神奇的东西,特别现在有很多Android库都是使用注解的方式来实现的.一直想详细了解一下其中的原理.很有幸阅读到一篇详细解释编写注解处理器的文章.本文的 ...

  8. java中result的作用_JAVA中的Resultset

    JAVA中的Resultset (2012-04-21 14:53:34) 标签: it JAVA中Resultset是一个类 . 结果集(ResultSet)是数据中查询结果返回的一种对象,可以说结 ...

  9. java的复合语句的作用_Java复合语句的使用方法详解

    与 C 语言及其他语言相同, Java 语言的复合语句是以整个块区为单位的语句,所以又称为块语句.下面我们来看看有关复合语句的使用方法和实例. 复合语句由开括号"{"开始,闭括号& ...

最新文章

  1. SQL SERVER特殊行转列案列一则
  2. 数学基础学习随笔--序言
  3. 8个字典常用的内置函数,一次性给你总结了!
  4. 返回值是内置类型 不能更改_选择通过更改内容类型返回的详细程度,第二部分...
  5. shell编程题(三)
  6. 文本聚类分析算法_聚类分析算法综述
  7. Qt resizeEvent 控件居中设置
  8. Go-fastdfs分布式文件系统搭建
  9. 软考 系统分析师教程 免费拿走不谢
  10. ARKit入门到精通-1.5 -基础内容-史小川-专题视频课程
  11. 区块链技术之P2P网络(一)
  12. fiddler Android下https抓包全攻略
  13. 【词性标注】一篇文章弄懂词性标注
  14. 【定量分析、量化金融与统计学】R语言方差分析的outliers陷阱
  15. 定时器输出的PWM频率范围及占空比精度
  16. 【题解】【循环】幂级数求和
  17. matlab错误dparsfa,Dpabi安装出错,求助大大佬
  18. 渲染效果图哪家好?2022最新实测(三)
  19. 开发者福利chatGPT软件Build Software. Fast.
  20. 【邮政编码识别】基于计算机视觉实现邮政编码识别含Matlab源码

热门文章

  1. 终于有人把P2P、P2C、O2O、B2C、B2B、C2C 的区别讲透了
  2. 自定义View和控件
  3. python 获取当前日期和时间,Python中获取当前日期和时间的方法详解
  4. PMP复习整理考点篇【4】--- 质量成本
  5. 草根站长如何赚到人生第一个100万
  6. 日常代码工具(快速索引)
  7. 笔记本电脑因安装软件重启导致黑屏?
  8. Redis:基于SETNX解决分布式锁误删问题
  9. 入门级别的Python爬虫代码 爬取百度上的图片
  10. 机器学习的评价指标(二)-SSE、MSE、RMSE、MAE、R-Squared