深入理解Java:内省(Introspector)

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

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

  例如类UserInfo :

package com.peidasoft.Introspector;

public class UserInfo {

    private long userId;
private String userName;
private int age;
private String emailAddress; public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
} }

  在类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.peidasoft.Introspector;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method; public class BeanInfoUtil {

public static void setProperty(UserInfo userInfo,String userName)throws Exception{
PropertyDescriptor propDesc=new PropertyDescriptor(userName,UserInfo.class);
Method methodSetUserName=propDesc.getWriteMethod();
methodSetUserName.invoke(userInfo, "wong");
System.out.println("set userName:"+userInfo.getUserName());
}

public static void getProperty(UserInfo userInfo,String userName)throws Exception{
PropertyDescriptor proDescriptor =new PropertyDescriptor(userName,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.peidasoft.Introspector;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method; public class BeanInfoUtil { public static void setPropertyByIntrospector(UserInfo userInfo,String userName)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(userName)){
Method methodSetUserName=propDesc.getWriteMethod();
methodSetUserName.invoke(userInfo, "alan");
System.out.println("set userName:"+userInfo.getUserName());
break;
}
}
}
} public static void getPropertyByIntrospector(UserInfo userInfo,String userName)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(userName)){
Method methodGetUserName=propDesc.getReadMethod();
Object objUserName=methodGetUserName.invoke(userInfo);
System.out.println("get userName:"+objUserName.toString());
break;
}
}
}
} }

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

  使用实例:

package com.peidasoft.Introspector;

public class BeanInfoTest {

    /**
* @param args
*/
public static void main(String[] args) {
UserInfo userInfo=new UserInfo();
userInfo.setUserName("peida");
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:peida
set userName:wong
get userName:wong
set userName:alan
get userName:alan
java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.peidasoft.Introspector.BeanInfoUtil.setProperty(BeanInfoUtil.java:14)
at com.peidasoft.Introspector.BeanInfoTest.main(BeanInfoTest.java:22) 

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

  BeanUtils工具包:


  由上述可看出,内省操作非常的繁琐,所以所以Apache开发了一套简单、易用的API来操作Bean的属性——BeanUtils工具包。
  BeanUtils工具包:下载:http://commons.apache.org/beanutils/ 注意:应用的时候还需要一个logging包 http://commons.apache.org/logging/
  使用BeanUtils工具包完成上面的测试代码:

package com.peidasoft.Beanutil;

import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils; import com.peidasoft.Introspector.UserInfo; public class BeanUtilTest {
public static void main(String[] args) {
UserInfo userInfo=new UserInfo();
try {
BeanUtils.setProperty(userInfo, "userName", "peida"); 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()); PropertyUtils.setProperty(userInfo, "age", "8");
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}

  运行结果:

set userName:peida
get userName:peida
set age:18
get age:18
get userName type:java.lang.String
get age type:java.lang.String
8
java.lang.Integer
Exception in thread "main" java.lang.IllegalArgumentException: Cannot invoke com.peidasoft.Introspector.UserInfo.setAge
on bean class 'class com.peidasoft.Introspector.UserInfo' - argument type mismatch - had objects of type "java.lang.String"
but expected signature "int"
at org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2235)
at org.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:2151)
at org.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1957)
at org.apache.commons.beanutils.PropertyUtilsBean.setProperty(PropertyUtilsBean.java:2064)
at org.apache.commons.beanutils.PropertyUtils.setProperty(PropertyUtils.java:858)
at com.peidasoft.orm.Beanutil.BeanUtilTest.main(BeanUtilTest.java:38)
Caused by: java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2170)
... 5 more

  说明:

  1.获得属性的值,例如,BeanUtils.getProperty(userInfo,"userName"),返回字符串
  2.设置属性的值,例如,BeanUtils.setProperty(userInfo,"age",8),参数是字符串或基本类型自动包装。设置属性的值是字符串,获得的值也是字符串,不是基本类型。   3.BeanUtils的特点:
    1). 对基本数据类型的属性的操作:在WEB开发、使用中,录入和显示时,值会被转换成字符串,但底层运算用的是基本类型,这些类型转到动作由BeanUtils自动完成。
    2). 对引用数据类型的属性的操作:首先在类中必须有对象,不能是null,例如,private Date birthday=new Date();。操作的是对象的属性而不是整个对象,例如,BeanUtils.setProperty(userInfo,"birthday.time",111111);   

package com.peidasoft.Introspector;
import java.util.Date; public class UserInfo { private Date birthday = new Date(); public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getBirthday() {
return birthday;
}
}
package com.peidasoft.Beanutil;

import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.BeanUtils;
import com.peidasoft.Introspector.UserInfo; public class BeanUtilTest {
public static void main(String[] args) {
UserInfo userInfo=new UserInfo();
try {
BeanUtils.setProperty(userInfo, "birthday.time","111111");
Object obj = BeanUtils.getProperty(userInfo, "birthday.time");
System.out.println(obj);
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}

  3.PropertyUtils类和BeanUtils不同在于,运行getProperty、setProperty操作时,没有类型转换,使用属性的原有类型或者包装类。由于age属性的数据类型是int,所以方法PropertyUtils.setProperty(userInfo, "age", "8")会爆出数据类型不匹配,无法将值赋给属性。

  参考资料:


  1.http://www.cnblogs.com/avenwu/archive/2012/02/28/2372586.html

  2.http://blog.csdn.net/zhuruoyun/article/details/8219333

深入理解Java:内省(Introspector)的更多相关文章

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

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

  2. Java 内省(Introspector)和 BeanUtils

    人生若只如初见,何事秋风悲画扇. 概述 内省(Introspector) 是Java 语言对 JavaBean 类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类,主要用于传递数据信息, ...

  3. JAVA内省(Introspector)

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

  4. 聊聊Java内省Introspector

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

  5. Java 内省 Introspector

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

  6. java内省Introspector

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

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

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

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

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

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

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

随机推荐

  1. 实现Redhat Linux 6和Windows通过Windows Server AD统一认证并共享访问Oracle ZS存储系统

    Windows Server 2012 AD设置 1.  建立新的组织单位OU 为用户提前建立好OU,是为了AD用户管理简单清晰. 2.  建立新的用户和用户组 建立新的用户的时候,要同时将用户归属到 ...

  2. Django之admin的使用和源码剖析

    admin组件使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.你可以在项目的 settings.py 中的 INSTALLE ...

  3. mysql性能优化之-innodb_flush_log_at_trx_commit

    innodb_flush_log_at_trx_commit是配置MySql日志何时写入硬盘的参数: 一.参数值说明 0:log buffer将每秒一次地写入log file中,并且log file的 ...

  4. weblogic上服务器建立

    weblogic上服务器建立

  5. 【转】H.264中的NAL技术

    NAL技术 1.NAL概述 NAL全称Network Abstract Layer,即网络抽象层.在H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面 ...

  6. Mybatis 系列10

    在前九篇中,介绍了mybatis的配置以及使用, 那么本篇将走进mybatis的源码,分析mybatis 的执行流程 1. SqlSessionFactory 与 SqlSession. 通过前面的章 ...

  7. 中文字体名称对照表(unicode码)及20个web安全字体

    在Web编码中,CSS默认应用的Web字体是有限的,虽然在新版本的CSS3,我们可以通过新增的@font-face属性来引入特殊的浏览器加载字体.但多数情况下,考虑各个因素的影响我们还是在尽量充分利用 ...

  8. Pydev Console中文提示乱码的问题

    1. 像这样的规则内容请这样处理"\u305d\u3093\u306a\u306b"style unicode string : print str.decode("un ...

  9. log4j2.xml全配置文件

    可以参考如下配置 <?xml version="1.0" encoding="UTF-8"?> <!--日志级别以及优先级排序: OFF &g ...

  10. codeforces——961A Tetris

    本文是博主原创文章,未经允许不得转载. 我在csdn上也同步发布了此文,链接 https://blog.csdn.net/umbrellalalalala/article/details/798915 ...