人生若只如初见,何事秋风悲画扇。

概述

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

JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进JavaBean中,这种对象称为“值对象”(Value Object),或“VO”。方法比较少。这些信息储存在类的私有变量中,通过set()、get()获得。例如UserInfo

package com.niocoder.test.introspector;

/**
*
*/
public class UserInfo {
private String userName;
private Integer age;
private String webSite; public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public String getUserName() {
return userName;
} public void setUserName(String userName) {
this.userName = userName;
} public String getWebSite() {
return webSite;
} public void setWebSite(String webSite) {
this.webSite = webSite;
}
}

在类UserInfo中有属性 userName, 那我们可以通过 getUserName,setUserName来得到其值或者设置新的值。通过 getUserName/setUserName来访问 userName属性,这就是默认的规则。 Java JDK中提供了一套 API 用来访问某个属性的 getter/setter 方法,这就是内省。

JDK内省类库:

PropertyDescriptor

PropertyDescriptor类表示JavaBean类通过存储器导出一个属性。主要方法:

  1. getPropertyType(),获得属性的Class对象;
  2. getReadMethod(),获得用于读取属性值的方法;getWriteMethod(),获得用于写入属性值的方法;
  3. hashCode(),获取对象的哈希值;
  4. setReadMethod(Method readMethod),设置用于读取属性值的方法;
  5. setWriteMethod(Method writeMethod),设置用于写入属性值的方法。
package com.niocoder.test.introspector;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method; public class BeanInfoUtil {
/**
* @param userInfo 实例
* @param propertyName 属性名
* @throws Exception
*/
public static void setProperty(UserInfo userInfo, String propertyName) throws Exception {
PropertyDescriptor propDesc = new PropertyDescriptor(propertyName, UserInfo.class);
Method methodSetUserName = propDesc.getWriteMethod();
methodSetUserName.invoke(userInfo, "郑龙飞");
System.out.println("set userName:" + userInfo.getUserName());
} /**
* @param userInfo 实例
* @param propertyName 属性名
* @throws Exception
*/
public static void getProperty(UserInfo userInfo, String propertyName) throws Exception {
PropertyDescriptor proDescriptor = new PropertyDescriptor(propertyName, UserInfo.class);
Method methodGetUserName = proDescriptor.getReadMethod();
Object objUserName = methodGetUserName.invoke(userInfo);
System.out.println("get userName:" + objUserName.toString());
}
}

Introspector

将JavaBean中的属性封装起来进行操作。在程序把一个类当做JavaBean来看,就是调用Introspector.getBeanInfo()方法,得到的BeanInfo对象封装了把这个类当做JavaBean看的结果信息,即属性的信息。

getPropertyDescriptors(),获得属性的描述,可以采用遍历BeanInfo的方法,来查找、设置类的属性。具体代码如下:

package com.niocoder.test.introspector;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method; public class BeanInfoUtil { /**
* @param userInfo 实例
* @param propertyName 属性名
* @throws Exception
*/
public static void setPropertyByIntrospector(UserInfo userInfo, String propertyName) throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(UserInfo.class);
PropertyDescriptor[] proDescrtptors = beanInfo.getPropertyDescriptors();
if (proDescrtptors != null && proDescrtptors.length > 0) {
for (PropertyDescriptor propDesc : proDescrtptors) {
if (propDesc.getName().equals(propertyName)) {
Method methodSetUserName = propDesc.getWriteMethod();
methodSetUserName.invoke(userInfo, "niocoder");
System.out.println("set userName:" + userInfo.getUserName());
break;
}
}
}
} /**
* @param userInfo 实例
* @param propertyName 属性名
* @throws Exception
*/
public static void getPropertyByIntrospector(UserInfo userInfo, String propertyName) throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(UserInfo.class);
PropertyDescriptor[] proDescrtptors = beanInfo.getPropertyDescriptors();
if (proDescrtptors != null && proDescrtptors.length > 0) {
for (PropertyDescriptor propDesc : proDescrtptors) {
if (propDesc.getName().equals(propertyName)) {
Method methodGetUserName = propDesc.getReadMethod();
Object objUserName = methodGetUserName.invoke(userInfo);
System.out.println("get userName:" + objUserName.toString());
break;
}
}
}
} }

通过这两个类的比较可以看出,都是需要获得PropertyDescriptor,只是方式不一样:前者通过创建对象直接获得,后者需要遍历,所以使用PropertyDescriptor类更加方便。

Test

BeanInfoTest

public class BeanInfoTest {

    public static void main(String[] args) {
UserInfo userInfo = new UserInfo();
userInfo.setUserName("merryyou");
try {
BeanInfoUtil.getProperty(userInfo, "userName"); BeanInfoUtil.setProperty(userInfo, "userName"); BeanInfoUtil.getProperty(userInfo, "userName"); BeanInfoUtil.setPropertyByIntrospector(userInfo, "userName"); BeanInfoUtil.getPropertyByIntrospector(userInfo, "userName"); BeanInfoUtil.setProperty(userInfo, "age"); } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
}

输出

get userName:merryyou
set userName:郑龙飞
get userName:郑龙飞
set userName:niocoder
get userName:niocoder
Disconnected from the target VM, address: '127.0.0.1:65243', transport: 'socket'
java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.niocoder.test.introspector.BeanInfoUtil.setProperty(BeanInfoUtil.java:13)
at com.niocoder.test.introspector.BeanInfoTest.main(BeanInfoTest.java:19)

说明:BeanInfoUtil.setProperty(userInfo, "age");报错是应为age属性是int数据类型,而setProperty方法里面默认给age属性赋的值是String类型。所以会爆出argument type mismatch参数类型不匹配的错误信息。

BeanUtils

由上述可看出,内省操作非常的繁琐,所以所以Apache开发了一套简单、易用的API来操作Bean的属性——BeanUtils工具包。

  • BeanUtils.getProperty(Object bean, String propertyName)
  • BeanUtils.setProperty(Object bean, String propertyName, Object value)

BeanUtilTest

public class BeanUtilTest {

    public static void main(String[] args) {

        UserInfo userInfo = new UserInfo();
try { BeanUtils.setProperty(userInfo, "userName", "郑龙飞");
System.out.println("set userName:" + userInfo.getUserName());
System.out.println("get userName:" + BeanUtils.getProperty(userInfo, "userName")); BeanUtils.setProperty(userInfo, "age", 18);
System.out.println("set age:" + userInfo.getAge());
System.out.println("get age:" + BeanUtils.getProperty(userInfo, "age"));
System.out.println("get userName type:" + BeanUtils.getProperty(userInfo, "userName").getClass().getName());
System.out.println("get age type:" + BeanUtils.getProperty(userInfo, "age").getClass().getName()); PropertyUtils.setProperty(userInfo, "age", 8);
System.out.println(PropertyUtils.getProperty(userInfo, "age"));
System.out.println(PropertyUtils.getProperty(userInfo, "age").getClass().getName());
// 特殊 age属性为Integer类型
PropertyUtils.setProperty(userInfo, "age", "8");
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}

输出

set userName:郑龙飞
get userName:郑龙飞
set age:18
get age:18
get userName type:java.lang.String
get age type:java.lang.String
8
java.lang.Integer
Disconnected from the target VM, address: '127.0.0.1:50244', transport: 'socket'
Exception in thread "main" java.lang.IllegalArgumentException: Cannot invoke com.niocoder.test.introspector.UserInfo.setAge on bean class 'class com.niocoder.test.introspector.UserInfo' - argument type mismatch - had objects of type "java.lang.String" but expected signature "java.lang.Integer"
at org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2195)
at org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:2108)
at org.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1914)
at org.apache.commons.beanutils.PropertyUtilsBean.setProperty(PropertyUtilsBean.java:2021)
at org.apache.commons.beanutils.PropertyUtils.setProperty(PropertyUtils.java:896)
at com.niocoder.test.introspector.BeanUtilTest.main(BeanUtilTest.java:28)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2127)
... 5 more Process finished with exit code 1

代码下载

参考链接

Java 内省(Introspector)和 BeanUtils的更多相关文章

  1. Java 内省(Introspector)深入理解

    Java 内省(Introspector)深入理解 一些概念: 内省(Introspector) 是Java 语言对 JavaBean 类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类 ...

  2. JAVA内省(Introspector)

    什么是Java内省:内省是Java语言对Bean类属性.事件的一种缺省处理方法. Java内省的作用:一般在开发框架时,当需要操作一个JavaBean时,如果一直用反射来操作,显得很麻烦:所以sun公 ...

  3. 聊聊Java内省Introspector

    前提 这篇文章主要分析一下Introspector(内省,应该读xing第三声,没有找到很好的翻译,下文暂且这样称呼)的用法.Introspector是一个专门处理JavaBean的工具类,用来获取J ...

  4. Java 内省 Introspector

    操纵类的属性,有两种方法 反射 内省 面向对象的编程中,对于用户提交过来的数据,要封装成一个javaBean,也就是对象 其中Bean的属性不是由字段来决定的,而是由get和Set方法来决定的 pub ...

  5. java内省Introspector

    大纲: JavaBean 规范 内省 一.JavaBean 规范 JavaBean —般需遵循以下规范. 实现 java.io.Serializable 接口. javaBean属性是具有getter ...

  6. 【小家Spring】Spring IoC是如何使用BeanWrapper和Java内省结合起来给Bean属性赋值的

    #### 每篇一句 > 具备了技术深度,遇到问题可以快速定位并从根本上解决.有了技术深度之后,学习其它技术可以更快,再深入其它技术也就不会害怕 #### 相关阅读 [[小家Spring]聊聊Sp ...

  7. 【小家Spring】聊聊Spring中的数据绑定 --- BeanWrapper以及内省Introspector和PropertyDescriptor

    #### 每篇一句 > 千古以来要饭的没有要早饭的,知道为什么吗? #### 相关阅读 [[小家Spring]聊聊Spring中的数据转换:Converter.ConversionService ...

  8. 深入理解Java:内省(Introspector)

    深入理解Java:内省(Introspector) 内省(Introspector) 是Java 语言对 JavaBean 类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类,主要用于传 ...

  9. (转载)深入理解Java:内省(Introspector)

    本文转载自:https://www.cnblogs.com/peida/archive/2013/06/03/3090842.html 一些概念: 内省(Introspector) 是Java 语言对 ...

随机推荐

  1. jmeter界面字体修改

    实际应用中发现,同样是win10系统,显示器屏幕尺寸大小不同,jmeter界面字体展示也不一样,标准屏幕还可以,大屏幕下不能自动适应屏幕大小放大而且还变的更小.在查询解决方法时,发现有朋友出现类似情况 ...

  2. c# 多进程写信息到前台控件

    private void DispMsg(string strMsg, bool clearlb = false) { if (this.lberror.InvokeRequired == false ...

  3. Java网络编程 -- 网络协议

    OSI网络七层协议 为使不同计算机厂家的计算机能够互相通信,以便在更大的范围内建立计算机网络,有必要建立一个国际范围的网络体系结构标准.OSI网络七层协议就是在这个基础上制定出来的,其从最底层开始依次 ...

  4. Prometheus 集成 Node Exporter

    文章首发于公众号<程序员果果> 地址:https://mp.weixin.qq.com/s/40ULB9UWbXVA21MxqnjBxw 简介 Prometheus 官方和一些第三方,已经 ...

  5. leetcode bug free

    ---不包含jiuzhang ladders中出现过的题.如出现多个方法,则最后一个方法是最优解. 目录: 1 String 2 Two pointers 3 Array 4 DFS &&am ...

  6. springBoot入门教程(图文+源码+sql)

    springBoot入门 1   springBoot 1.1 SpringBoot简介 Spring Boot让我们的Spring应用变的更轻量化.比如:你可以仅仅依靠一个Java类来运行一个Spr ...

  7. Oracle中的字符函数

    Oracle中常用的字符串函数有以下几种: 1.upper()---将字符串的内容全部转换为大写.lower()---将字符串的内容全部转换为小写.具体用法: select  upper('test' ...

  8. pip安装第三方库

    不是所有的第三方Python包都能通过pip来安装,只能是发布在pypi.org上面的才能通过pip安装. pypi是什么? pypi是一个仓库,上面存放了大量的Python第三方软件包,是由Pyth ...

  9. Coablt strike官方教程中文版

    安装和设置 系统要求 Cobalt Strike的最低系统要求 2 GHz +以上的cpu 2 GB RAM 500MB +可用空间 在Amazon的EC2上,至少使用较高核数的CPU(c1.medi ...

  10. idea快速生成实体类

    1.打开idea的视图,选择Database 2.选择对应的数据库[这里是mysql为例] 3.输入自己对应的内容,输入完成可点击Test Connection进行测试,成功SUCCESS 4.点击确 ...