內省和反射有什么區別:
反射式在運行狀態把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則是將該屬性的值轉換成字符串后才返回。