深入理解JavaBean内省

来源:互联网 发布:第七感双色球软件 编辑:程序博客网 时间:2024/06/03 20:59

<span style="font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">内省(Introspector) </span><span style="background-color: rgb(255, 255, 255); margin: 0px; padding: 0px; color: rgb(54, 46, 43); font-family: Arial; font-size: 14px; line-height: 26px;">是Java 语言对 JavaBean 类属性、事件的一种缺省处理方法。</span>

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

例如类User

package com.anchor.Bean;public class User {private String userName;private int age;private String emailAddress;private int userID;public synchronized String getUserName() {return userName;}public synchronized void setUserName(String userName) {this.userName = userName;}public synchronized int getAge() {return age;}public synchronized void setAge(int age) {this.age = age;}public synchronized String getEmailAddress() {return emailAddress;}public synchronized void setEmailAddress(String emailAddress) {this.emailAddress = emailAddress;}public synchronized int getUserID() {return userID;}public synchronized void setUserID(int userID) {this.userID = userID;}}

在类User中有属性 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.anchor.Bean;import java.beans.BeanInfo;import java.beans.IntrospectionException;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class UserBeanUtil {
public static void setProperty(User user,String userName) throws Exception{PropertyDescriptor propDesc=new PropertyDescriptor(userName, User.class);//获取javaBean描述器Method setUserName=propDesc.getWriteMethod();//得到写入方法,即setUserName()方法setUserName.invoke(user, "Tom");//调用serUserName()方法,设置用户名System.out.println("Set UserName:"+user.getUserName());//调用get方法得到用户名}public static void getProperty(User user,String userName) throws Exception{PropertyDescriptor propDesc=new PropertyDescriptor(userName, User.class);Method getUserName=propDesc.getReadMethod();Object objectUserName=getUserName.invoke(user);System.out.println("Get UserName:"+objectUserName.toString());}

Introspector类:

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

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

public static void setPropertyByIntrospector(User user,String userName) throws Exception{BeanInfo beanInfo = Introspector.getBeanInfo(User.class);//通过Introspector内省类调用getBeanInfo,得到BeanInfo//对象,里面封装了JavaBean中的属性信息PropertyDescriptor [] propertyDescriptors=beanInfo.getPropertyDescriptors();//得到beanInfo中的所有属性描述器if(propertyDescriptors!= null&&propertyDescriptors.length>0){//遍历得到userName 的属性描述器for(PropertyDescriptor proDesc:propertyDescriptors){if(proDesc.getName().equals(userName)){//如果得到属性为userName的属性Method setUserName=proDesc.getWriteMethod();setUserName.invoke(user, "Jack");System.out.println("Set userName BY Introspctor:"+user.getUserName());break;}}}}public static void getPropertiByIntrospector(User user,String userName) throws Exception{BeanInfo beanInfo = Introspector.getBeanInfo(User.class);PropertyDescriptor [] propertyDescriptors = beanInfo.getPropertyDescriptors();if(propertyDescriptors != null&& propertyDescriptors.length>0){for(PropertyDescriptor propDesc: propertyDescriptors){if(propDesc.getName().equals(userName)){Method getUserName = propDesc.getReadMethod();Object userNameOnject = getUserName.invoke(user);System.out.println("Get userName BY Introspector:" + userNameOnject.toString());break;}}}}

使用实例:

package com.anchor.Bean;public class UserBeanUtilTest {public static void main(String[] args) throws Exception {User user = new User();user.setUserName("Jay");UserBeanUtil.getProperty(user, "userName");UserBeanUtil.setProperty(user,"userName");UserBeanUtil.getProperty(user, "userName");System.out.println("-------------------------");UserBeanUtil.getPropertiByIntrospector(user, "userName");UserBeanUtil.setPropertyByIntrospector(user, "userName");UserBeanUtil.getPropertiByIntrospector(user,"userName");System.out.println("-------------------------");UserBeanUtil.getProperty(user, "age");UserBeanUtil.setProperty(user,"age");}}
输出结果:

Get UserName:JaySet UserName:TomGet UserName:Tom-------------------------Get userName BY Introspector:TomSet userName BY Introspctor:JackGet userName BY Introspector:Jack-------------------------Get UserName:0Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatchat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)at java.lang.reflect.Method.invoke(Unknown Source)at com.anchor.Bean.UserBeanUtil.setProperty(UserBeanUtil.java:34)at com.anchor.Bean.UserBeanUtilTest.main(UserBeanUtilTest.java:18)

说明:
UserBeanUtil<span style="font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255); margin: 0px; padding: 0px;">.setProperty(user, </span><span style="font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">"age"</span><span style="font-family: Verdana, Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255); margin: 0px; padding: 0px;">);报错是应为age属性是int数据类型,而<span style="margin: 0px; padding: 0px;">setProperty方法里面默认给age属性赋的值是String类型。所以会爆出argument type mismatch参数类型不匹配的错误信息。</span></span>


 BeanUtils工具包:


 

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

package com.anchor.Bean;import java.lang.reflect.InvocationTargetException;import org.apache.commons.beanutils.BeanUtils;import org.apache.commons.beanutils.PropertyUtils;public class BeanUtilTest {public static void main(String[] args) throws Exception {User user = new  User();System.out.println("----使用BeanUtils-设置属性------");BeanUtils.setProperty(user, "userName", "Tom");System.out.println("user.getUserName(): "+user.getUserName());System.out.println("BeanUtils.getProperty(user, 'userName'): "+BeanUtils.getProperty(user, "userName"));System.out.println(BeanUtils.getProperty(user, "userName").getClass().getName());System.out.println("----------------------------");BeanUtils.setProperty(user, "age", "19");//年龄使用String类型会自动转换System.out.println("user.getAge(): "+user.getAge());System.out.println("BeanUtils.getProperty(user, 'age'): "+BeanUtils.getProperty(user, "age"));System.out.println(BeanUtils.getProperty(user, "age").getClass().getName());System.out.println("------使用PropertyUtil设置属性---------------");PropertyUtils.setProperty(user, "userName", "Jay");System.out.println("PropertyUtils.getProperty(user, 'userName'): "+PropertyUtils.getProperty(user, "userName"));System.out.println("-----------------");PropertyUtils.setProperty(user, "age", 10);System.out.println("PropertyUtils.getProperty(user, 'age'): "+PropertyUtils.getProperty(user, "age"));PropertyUtils.setProperty(user, "age", "12");//不会自动转换会报错}}

运行结果:

----使用BeanUtils-设置属性------user.getUserName(): TomBeanUtils.getProperty(user, 'userName'): Tomjava.lang.String----------------------------user.getAge(): 19BeanUtils.getProperty(user, 'age'): 19java.lang.String------使用PropertyUtil设置属性---------------PropertyUtils.getProperty(user, 'userName'): Jay-----------------PropertyUtils.getProperty(user, 'age'): 10Exception in thread "main" java.lang.IllegalArgumentException: Cannot invoke com.anchor.Bean.User.setAge on bean class 'class com.anchor.Bean.User' - 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.anchor.Bean.BeanUtilTest.main(BeanUtilTest.java:29)Caused by: java.lang.IllegalArgumentException: argument type mismatchat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)at java.lang.reflect.Method.invoke(Unknown Source)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);   

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


0 0
原创粉丝点击