内省与JavaBean

概述

JavaBean代表一类特殊的Java类,这种类主要用来存储和传递属性信息,JavaBean中的方法主要用于设置和获取这些私有属性,他们有一定的命名规则,我们可以把它们想象为一个侧重属性信息的类,如JSP中的表单信息打包一样,这些信息就可以封装在一个JavaBean对象中,通过一些特殊的方式来操作。

Introspector,即为内省

public class Introspector
extends Object

Introspector 类为通过工具学习有关受目标 Java Bean 支持的属性、事件和方法的知识提供了一个标准方法。

简单说,Introspector就是一种操作JavaBean的标准方式

JavaBean一些简单操作

写一个Bean类用作测试

   1: public class Bean {
   2:     private String name;
   3:     private int age;
   4:     private int num;
   5:     private int score;
   6:     
   7:     public Bean(String name, int age, int num, int score) {
   8:         super();
   9:         this.name = name;
  10:         this.age = age;
  11:         this.num = num;
  12:         this.score = score;
  13:     }
  14:     public String getName() {
  15:         return name;
  16:     }
  17:     public void setName(String name) {
  18:         this.name = name;
  19:     }
  20:     public int getAge() {
  21:         return age;
  22:     }
  23:     public void setAge(int age) {
  24:         this.age = age;
  25:     }
  26:     public int getNum() {
  27:         return num;
  28:     }
  29:     public void setNum(int num) {
  30:         this.num = num;
  31:     }
  32:     public int getScore() {
  33:         return score;
  34:     }
  35:     public void setScore(int score) {
  36:         this.score = score;
  37:     }
  38: }

实现set和get方法的简单操作

   1: public class BeanTest {
   2:  
   3:     /**
   4:      * @param args
   5:      */
   6:     public static void main(String[] args) {
   7:         
   8:         //获取对象
   9:         Bean b = new Bean("Shawn",12,1,97);
  10:         //获取类字节码文件
  11:         Class beanClass = Bean.class;    
  12:         //设置需要操作的属性名
  13:         String propertyName = "name";
  14:         
  15:         //调用set和get方法
  16:         System.out.println(getProperty(beanClass, b, propertyName, null));
  17:         setProperty(beanClass, b, propertyName, new Object[]{"Feng"});
  18:         System.out.println(getProperty(beanClass, b, propertyName, null));
  19:                 
  20:     }
  21:     //封装javabean的set方法
  22:     private static void setProperty(Class beanClass,Object obj,String propertyName,Object[] values){
  23:         try {
  24:             //获取属性描述符对象
  25:             PropertyDescriptor pd = new PropertyDescriptor(propertyName, beanClass);
  26:             //得到set方法对象
  27:             Method setMethod = pd.getWriteMethod();
  28:             //利用反射执行set方法
  29:             setMethod.invoke(obj, values);
  30:         } catch (IllegalArgumentException e) {
  31:             // TODO Auto-generated catch block
  32:             e.printStackTrace();
  33:         } catch (IntrospectionException e) {
  34:             // TODO Auto-generated catch block
  35:             e.printStackTrace();
  36:         } catch (IllegalAccessException e) {
  37:             // TODO Auto-generated catch block
  38:             e.printStackTrace();
  39:         } catch (InvocationTargetException e) {
  40:             // TODO Auto-generated catch block
  41:             e.printStackTrace();
  42:         }
  43:     }
  44:     //封装javabean的get方法
  45:     private static Object getProperty(Class beanClass,Object obj,String propertyName,Object[] args){
  46:         Object retVal = null;
  47:         try {
  48:             //获取属性描述符对象
  49:             PropertyDescriptor pd = new PropertyDescriptor(propertyName, beanClass);
  50:             //得到get方法对象
  51:             Method getMethod = pd.getReadMethod();
  52:             //利用反射执行get方法
  53:             retVal = getMethod.invoke(obj, args);
  54:         } catch (IllegalArgumentException e) {
  55:             // TODO Auto-generated catch block
  56:             e.printStackTrace();
  57:         } catch (IntrospectionException e) {
  58:             // TODO Auto-generated catch block
  59:             e.printStackTrace();
  60:         } catch (IllegalAccessException e) {
  61:             // TODO Auto-generated catch block
  62:             e.printStackTrace();
  63:         } catch (InvocationTargetException e) {
  64:             // TODO Auto-generated catch block
  65:             e.printStackTrace();
  66:         }
  67:         return retVal;
  68:     }
  69: }

利用内省实现一些复杂操作

   1: public class BeanTest2 {
   2:  
   3:     /**
   4:      * @param args
   5:      * @throws IntrospectionException 
   6:      * @throws InvocationTargetException 
   7:      * @throws IllegalAccessException 
   8:      * @throws IllegalArgumentException 
   9:      */
  10:     public static void main(String[] args) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
  11:         
  12:         //获取对象
  13:         Bean b = new Bean("Shawn",12,1,97);
  14:         //获取类字节码文件
  15:         Class beanClass = Bean.class;    
  16:         //设置需要操作的属性名
  17:         String propertyName = "name";
  18:         
  19:         //根据类字节码对象获取Bean信息
  20:         BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
  21:         //利用内省获取所有的属性描述符
  22:         PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
  23:         //遍历所有的属性描述符,找到要操作的属性,进行操作
  24:         for(PropertyDescriptor pd : pds){
  25:             if(pd.getName().equals(propertyName)){
  26:                 Method setMethod = pd.getWriteMethod();
  27:                 Method getMethod = pd.getReadMethod();
  28:                 System.out.println(getMethod.invoke(b, null));
  29:                 setMethod.invoke(b, "Feng");
  30:                 System.out.println(getMethod.invoke(b, null));
  31:             }
  32:         }
  33:     }
  34: }

BeanUtils工具包

BeanUtils工具包是apach提供的一套非常方便的用于操作JavaBean的工具

BeanUtil实现set和get方法

   1: public class BeanUtilTest {
   2:  
   3:     /**
   4:      * @param args
   5:      * @throws NoSuchMethodException 
   6:      * @throws InvocationTargetException 
   7:      * @throws IllegalAccessException 
   8:      */
   9:     public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  10:         
  11:         //获取对象
  12:         Bean b = new Bean("Shawn",12,1,97);
  13:         //设置需要操作的属性名
  14:         String propertyName = "score";
  15:         
  16:         //利用BeanUtils获取属性值
  17:         System.out.println(BeanUtils.getProperty(b, propertyName));
  18:         //利用BeanUtils设置属性值
  19:         BeanUtils.setProperty(b, propertyName, "33");
  20:         System.out.println(BeanUtils.getProperty(b, propertyName));
  21:     }
  22: }

我们可以看到,即便操作的是int型的属性,接收的仍然是字符串数据

BeanUtils包中还提供一个类PropertyUtils,也具有setProperty与getProperty的方法,与BeanUtils不同的是,传入的参数不需要进行类型转换,也就是说,如果BeanUtils中的方法类型转换出了问题时,可以采用PropertyUtils中的方法,直接传入对应类型的参数,同样可以达到目的。

同时,BeanUtils还支持属性的级联操作

比如一个人内部有心脏,而心脏内部又有左心房和右心房,那么我们可以直接通过BeanUtils设置和获取心脏的内部属性

   1: public class Heart{
   2:     private String left;
   3:     private String right;
   4:     public String getLeft() {
   5:         return left;
   6:     }
   7:     public void setLeft(String left) {
   8:         this.left = left;
   9:     }
  10:     public String getRight() {
  11:         return right;
  12:     }
  13:     public void setRight(String right) {
  14:         this.right = right;
  15:     }
  16: }
   1: public class Person{
   2:     private Heart heart = new Heart();
   3:     private Date birthday;
   4:     public Date getBirthday() {
   5:         return birthday;
   6:     }
   7:     public void setBirthday(Date birthday) {
   8:         this.birthday = birthday;
   9:     }
  10:     public Heart getHeart() {
  11:         return heart;
  12:     }
  13:     public void setHeart(Heart heart) {
  14:         this.heart = heart;
  15:     }
  16: }
   1: public class BeanUtilsTest2 {
   2:  
   3:     /**
   4:      * @param args
   5:      * @throws NoSuchMethodException 
   6:      * @throws InvocationTargetException 
   7:      * @throws IllegalAccessException 
   8:      */
   9:     public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  10:         // TODO Auto-generated method stub
  11:         Person p = new Person();
  12:         System.out.println(BeanUtils.getProperty(p, "heart.left"));
  13:         BeanUtils.setProperty(p, "heart.left", "lll");
  14:         System.out.println(BeanUtils.getProperty(p, "heart.left"));
  15:     }
  16: }

还有一个重要的操作,BeanUtils可以将Map集合对象与JavaBean对象的对应属性内容进行转换

   1: public class BeanUtilsTest3 {
   2:  
   3:     /**
   4:      * @param args
   5:      * @throws InvocationTargetException 
   6:      * @throws IllegalAccessException 
   7:      * @throws NoSuchMethodException 
   8:      */
   9:     public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
  10:         
  11:         //将JavaBean的属性信息映射到一个Map集合中
  12:         Map map = new HashMap();
  13:         Bean b = new Bean("Shawn", 12, 14, 90);        
  14:         map = BeanUtils.describe(b);
  15:         System.out.println(map);
  16:         
  17:         //将map集合中的属性写入到JavaBean对象中
  18:         map = new HashMap();
  19:         map.put("name", "Feng");
  20:         map.put("score", 22);        
  21:         BeanUtils.populate(b, map);
  22:         System.out.println(b.toString());
  23:     }
  24: }

以上三点便是BeanUtils最常用的一些操作和特点,可以看到,BeanUtils的操作非常方便快捷,现在已经很普及了

JavaBean的命名规则

由于JavaBean中只有set和get方法是对外可见的,所以JavaBean内部属性用什么名字并不重要,只要设置好方法名称即可

一般规则是

如果方法名称为setXxx和getXxx,那么表示propertyName全为小写xxx

如果方法名称为setXXx或者setXXX,那么表示propertyName为对应的XXx以及XXX

一般setXxx以及setXXX比较常见,一个代表普通的变量,一个代表具有特殊含义的变量

所以我们写方法名称时尽量按照这个命名规则写,设置propertyName时使用相对应的名称即可

posted @ 2013-12-06 19:23  ShawnWithSmallEyes  阅读(416)  评论(0编辑  收藏  举报