內省(Introspector)是專門用來操作JavaBean屬性的。不是所有的字段(Field)都能被稱之為屬性,只有某些字段具有getXXX或setXXX方法的才能稱之為屬性,當然要稱為是一個Bean還需要有一個無參的構造器,而內省就是對這些屬性進行操作。
我們先來看一個例子來數一數Javabean的屬性:
1 public class Person { 2 private String name; 3 private int age; 4 5 public String getName() { 6 return name; 7 } 8 public void setName(String name) { 9 this.name = name; 10 } 11 public int getAge() { 12 return age; 13 } 14 public void setAge(int age) { 15 this.age = age; 16 } 17 18 public String getAbc() { 19 return null; 20 } 21 }
這里面一共有多少屬性呢?
答案是4個,除了兩個私有字段提供了get或set 方法成為了這個類的屬性之外,還有外加的一個getXXX(那么屬性為xXX),最后還有一個從Object類中繼承的getClass方法(屬性為class),所以Person中含有4個屬性。
回歸到內省,當然僅僅操作是屬性,可以按操作字段一樣采用反射,但是采用內省會更加專業。
在JavaAPI中有專門的一個類封裝了內省的操作,這個類就是Introspector類,通過getBeanInfo(…)方法就可以將某個類中的屬性封裝到一個BeanInfo類中。
取得BeanInfo對象后就相當於取得某個類的所有屬性,那么再調用BeanInfo對象中的getPropertyDescriptors()方法獲得PropertyDescriptor[]數組對象,每個數組中的元素都是PropertyDescriptor實例(屬性描述器),而PropertyDescriptor實例封裝了每個屬性特有的一些性質,比如調用getReadMethod()方法就能獲得這個屬性的get方法Method,調用getWriteMethod()方法就能獲得這個屬性的set方法Method。
通過一段簡單的代碼來測試一下剛才Person這個bean對象到底有多少個屬性:
1 Person p = new Person(); 2 BeanInfo beanInfo = Introspector.getBeanInfo(p.getClass()); 3 PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); 4 for(PropertyDescriptor pd:pds) { 5 System.out.println(pd.getName()); 6 }
控制台觀察:
可以看到確實是有4個屬性。
如果我們不想有父類繼承的某些get或set方法而繼承下來的屬性,比如上述的class,那么我們在最開始使用Introspector. getBeanInfo時可以使用對應的參數列表:
當然這個方法也可以不需要某一級以上的父類屬性,非常靈活。
如果想直接操作一個bean的某個具體屬性,那么其實我們可以直接使用屬性描述器PropertyDescriptor的構造函數:
比如我想操作上述Person類的age屬性:
1 PropertyDescriptor pd = new PropertyDescriptor("age", Person.class); 2 Person p = new Person(); 3 Method setAgeMethod = pd.getWriteMethod(); 4 setAgeMethod.invoke(p,25); 5 Method getAgeMethod = pd.getReadMethod(); 6 System.out.println(getAgeMethod.invoke(p, null));
輸出:25
當然,獲得某個屬性的屬性描述器(PropertyDescriptor),調用getPropertyType方法還能知道該屬性的類型:
1 PropertyDescriptor pd = new PropertyDescriptor("age", Person.class); 2 System.out.println(pd.getPropertyType());
輸出: