Java内省详解

  内省和反射有什么区别:

  反射式在运行状态把Java类中的各种成分映射成相应的Java类,可以动态的获取所有的属性以及动态调用任意一个方法,强调的是运行状态。 
  内省机制是通过反射来实现的,BeanInfo用来暴露一个bean的属性、方法和事件,以后我们就可以操纵该JavaBean的属性。

  1.通过PropertyDescriptor修改属性方式

 1 public class BeanInfoUtil {  
 2     public static void setProperty(UserInfo userInfo,String userName)throws Exception{  
 3         PropertyDescriptor propDesc=new PropertyDescriptor(userName,UserInfo.class);  
 4         Method methodSetUserName=propDesc.getWriteMethod();  
 5         methodSetUserName.invoke(userInfo, "wong");  
 6         System.out.println("set userName:"+userInfo.getUserName());  
 7     }  
 8 
 9     public static void getProperty(UserInfo userInfo,String userName)throws Exception{  
10         PropertyDescriptor proDescriptor =new PropertyDescriptor(userName,UserInfo.class);  
11         Method methodGetUserName=proDescriptor.getReadMethod();  
12         Object objUserName=methodGetUserName.invoke(userInfo);  
13         System.out.println("get userName:"+objUserName.toString());  
14     }  
15 
16 }  

  2.通过Introspector类修改属性

 1 public class BeanInfoUtil2 {  
 2     public static void setPropertyByIntrospector(UserInfo userInfo,  
 3             String userName) throws Exception {  
 4 
 5         BeanInfo beanInfo = Introspector.getBeanInfo(UserInfo.class);  
 6         PropertyDescriptor[] proDescrtptors = beanInfo.getPropertyDescriptors();  
 7         if (proDescrtptors != null && proDescrtptors.length > 0) {  
 8             for (PropertyDescriptor propDesc : proDescrtptors) {  
 9                 if (propDesc.getName().equals(userName)) {  
10                     Method methodSetUserName = propDesc.getWriteMethod();  
11                     methodSetUserName.invoke(userInfo, "alan");  
12                     System.out  
13                             .println("set userName:" + userInfo.getUserName());  
14                     break;  
15                 }  
16             }  
17         }  
18     }  
19 
20     public static void getPropertyByIntrospector(UserInfo userInfo,  
21             String userName) throws Exception {  
22         BeanInfo beanInfo = Introspector.getBeanInfo(UserInfo.class);  
23         PropertyDescriptor[] proDescrtptors = beanInfo.getPropertyDescriptors();  
24         if (proDescrtptors != null && proDescrtptors.length > 0) {  
25             for (PropertyDescriptor propDesc : proDescrtptors) {  
26                 if (propDesc.getName().equals(userName)) {  
27                     Method methodGetUserName = propDesc.getReadMethod();  
28                     Object objUserName = methodGetUserName.invoke(userInfo);  
29                     System.out  
30                             .println("get userName:" + objUserName.toString());  
31                     break;  
32                 }  
33             }  
34         }  
35     }  
36 
37 }  

  注意事项,在上述修改JavaBean属性的时候,如果数据类型不对的话,会报错。例如BeanInfoUtil.setProperty(userInfo, “age”);报错是应为age属性是int数据类型,而setProperty方法里面默认给age属性赋的值是String类型。所以会爆出argument type mismatch参数类型不匹配的错误信息。 
  为了解决上述问题,Apache开发了一套简单、易用的API来操作Bean的属性——BeanUtils工具包。 

  

public static void main(String[] args) throws Exception {     
        Point point = new Point(2, 5);     
        String proName = "x";     
        BeanUtils.setProperty(point, proName, "8");     
        System.out.println(point.getX());// 8     
        System.out.println(BeanUtils.getProperty(point, proName));// 8     
        System.out.println(BeanUtils.getProperty(point, proName).getClass().getName());// java.lang.String     
        
        BeanUtils.setProperty(point, proName, 8);     
       System.out.println(BeanUtils.getProperty(point, proName).getClass().getName());// java.lang.String     
   }     
   //我们看到虽然属性x的类型是Integer,但是我们设置的时候无论是Integer还是String,BeanUtils的内部都是当成String来处理的。  

  BeanUtils支持javabean属性的级联操作;

 1 public static void main(String[] args) throws Exception {     
 2     Point point = new Point(2, 5);//在point中加一个属性 private Date birth = new Date();并产生setter/getter方法     
 3     String proName = "birth";     
 4     Date date= new Date();     
 5     date.setTime(10000);     
 6     BeanUtils.setProperty(point, proName, date);     
 7     System.out.println(BeanUtils.getProperty(point, proName));     
 8          
 9     BeanUtils.setProperty(point, "birth.time", 10000);     
10     System.out.println(BeanUtils.getProperty(point, "birth.time"));//10000     
11 }     
12 //之所以可以 BeanUtils.setProperty(point, "birth.time", 10000);这样写,那是因为Date类中有getTime()和setTime()方法,即Date类中相当于有time这个属性。   

  BeanUtils和PropertyUtils对比:

 1 public static void main(String[] args) throws Exception {     
 2     Point point = new Point(2, 5);     
 3     String proName = "x";     
 4     BeanUtils.setProperty(point, proName, "8");     
 5     System.out.println(BeanUtils.getProperty(point, proName));//8     
 6     System.out.println(BeanUtils.getProperty(point, proName).getClass().getName());//java.lang.String     
 7          
 8 // PropertyUtils.setProperty(point, proName, "8");//exception:argument type mismatch     
 9     PropertyUtils.setProperty(point, proName, 8);     
10     System.out.println(PropertyUtils.getProperty(point, proName));//8     
11     System.out.println(PropertyUtils.getProperty(point, proName).getClass().getName());//java.lang.Integer     
12 }     
13 //BeanUtils它以字符串的形式对javabean进行转换,而PropertyUtils是以原本的类型对javabean进行操作。如果类型不对,就会有argument type mismatch异常。  

  理解了相应的原理,那些现成的工具用起来就会更舒服,如Beanutils与 PropertyUtils工具。这两个工具设置属性的时候一个主要区别是PropertyUtils.getPropety方法获得的属性值的类型为该 属性本来的类型,而BeanUtils.getProperty则是将该属性的值转换成字符串后才返回。

posted @ 2017-08-13 11:42  ngulc  阅读(5957)  评论(0编辑  收藏  举报