JavaBean內省

1、什麼是JavaBean?

       JavaBean是一種特殊的Java類,主要用於傳遞數據信息,這種Java類中的方法主要用於訪問私有的字段,且方法名符合某種命名規則。


       如果要在兩個模塊之間傳遞多個信息,可以將這些信息封裝到一個JavaBean中,這種JavaBean的實例對象通常稱之爲值對象(Value Object,簡稱VO)。這些信息在類中用私有字段來存儲,如果讀取或設置這些字段的值,則需要通過一些相應的方法來訪問。


       JavaBean的屬性是根據其中的setter和getter方法來確定的,而不是根據其中的成員變量。如果方法名爲setId,中文意思即爲“設置id”,至於你把它存到哪個變量上,則不用管。如果方法名爲getId,中文意思即爲“獲取id”,至於你從哪個變量上取,也不用管。去掉set或者get前綴,剩餘部分就是屬性名。


注意:

     如果剩餘部分的第二個字母是小寫的,則把剩餘部分的首字母改成小的。

     如果剩餘部分的第二個字母是大寫的,則把剩餘部分保持不變,保持大寫。

例如:

     setId的屬性名是:id

     isLast的屬性名是:last

     setCPU的屬性名是:CPU

     getUPS的屬性名是:UPS

 

     總之,一個類被當作JavaBean使用時,JavaBean的屬性是根據方法名推斷出來的,它根本看不到java類內部的成員變量。


2、使用JavaBean的好處:

       一個符合JavaBean特點的類可以當作普通類一樣進行使用,但是把它當作JavaBean來使用會帶來以下一些額外的好處。

     ①、在Java EE開發中,經常要使用到JavaBean,很多環境都要去使用JavaBean方式進行操作。

     ②、JDK中提供了針對JavaBean進行操作的一些API,這套API就稱爲內省。如果自己通過getX方法來訪問私有的X,會有一定的難度。而用內省這套API操作JavaBean  比用普通類的方式更方便。

 

3、對JavaBean的簡單內省操作

需求:通過內省的方式對ReflectPoint類的對象中的成員變量進行讀寫操作。

代碼示例:

ReflectPoint.java

package cn.itcast.day1;
 
public class ReflectPoint {
      private int x;
      private int y;
 
      public ReflectPoint(int x, int y) {
         super();
         this.x = x;
         this.y = y;
      }
  
      public int getX() {
         return x;
      }
      public void setX(int x) {
         this.x = x;
      }
      public int getY() {
         return y;
      }
      public void setY(int y) {
         this.y = y;
      }
}

InstroSpectorTest.java

package cn.itcast.day1;
 
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
public class IntroSpectorTest {
      public static void main(String[]args) throws Exception{
         ReflectPoint pt1 = new ReflectPoint(3,5);
     
         String propertyName = "x";
         PropertyDescriptor pd1 = newPropertyDescriptor(propertyName, pt1.getClass());
         Method methodGetX = pd1.getReadMethod();
         Object retVal = methodGetX.invoke(pt1);
         System.out.println(retVal);    //結果:3
     
         PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());
         Method methodSetX = pd2.getWriteMethod();
         methodSetX.invoke(pt1,7);
         System.out.println(pt1.getX());    //結果:7
      }
}

 

Eclipse中方法抽取:

   抽取步驟:右鍵點擊需要被抽取的代碼,選擇Refactor(重構) → ExtractMethod(抽取方法) → 輸入抽取之後的方法名 → 點擊OK完成。



方法抽取完成之後的代碼如下:

IntroSpectorTest.java

package cn.itcast.day1;
 
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
public class IntroSpectorTest {
   public static void main(String[] args) throws Exception{
      ReflectPoint pt1 = new ReflectPoint(3,5);
     
      String propertyName = "x";
      Object retVal = getProperty(pt1, propertyName);
      System.out.println(retVal);
     
      Object value = 7;
      setProperty(pt1,propertyName, value);
      System.out.println(pt1.getX());
   }
 
   private static void setProperty(Object pt1, String propertyName,Objectvalue) throws IntrospectionException,IllegalAccessException,InvocationTargetException {
      PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, pt1.getClass());
      Method methodSetX = pd2.getWriteMethod();
      methodSetX.invoke(pt1,value);
   }
 
   private static Object getProperty(Object pt1, String propertyName) throws IntrospectionException,IllegalAccessException,InvocationTargetException{
      PropertyDescriptor pd1 = newPropertyDescriptor(propertyName, pt1.getClass());
      Method methodGetX = pd1.getReadMethod();
      Object retVal = methodGetX.invoke(pt1);
      return retVal;
   }
}

       注意:方法抽取完成之後,爲了使抽取後的方法具備通用性,一定要將方法中的某些參數的類型改爲Object,以便可以接收任何類型的參數。

 

4、對JavaBean的複雜內省操作

       採用遍歷BeanInfo類的所有屬性的方式來查找和設置某個ReflectPoint類的對象的x的屬性。

       在程序中把一個類當作JavaBean來看,就是調用InstroSpector.getBeanInfo()方法,得到的BeanInfo對象封裝了把這個類當作JavaBean看的結果信息。

 

代碼示例:

IntroSpectorTest.java

package cn.itcast.day1;
 
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 IntroSpectorTest {
       public static void main(String[] args) throws Exception {
         ReflectPoint pt1 = new ReflectPoint(3,5);
       
         String propertyName = "x";
         Object retVal = getProperty(pt1,propertyName);
         System.out.println(retVal);
       
         Object value = 7;
         setProperty(pt1, propertyName,value);
         System. out.println(pt1.getX());
       }
 
       private static void setProperty(Object pt1, String propertyName,Object value) throwsIntrospectionException,IllegalAccessException,InvocationTargetException {
         BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
         PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
         for (PropertyDescriptor pd : pds){
                if (pd.getName().equals(propertyName)){
                     Method methodSetX = pd.getWriteMethod();
                     methodSetX.invoke(pt1,value);
               }
         }
      }
 
       private static Object getProperty(Object pt1,String propertyName) throws IntrospectionException,IllegalAccessException, InvocationTargetException {
         BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
         PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
         Object retVal = null ;
         for (PropertyDescriptor pd : pds){
                if (pd.getName().equals(propertyName)){
                     Method methodGetX = pd.getReadMethod();
                     retVal = methodGetX.invoke(pt1);
               }
         }
         return retVal;
       }
}


5、使用BeanUtils工具包操作JavaBean

       要使用BeanUtils工具包,首先要到Apache的官網上去下載BeanUtils工具包(http://commons.apache.org/ ),下載完成之後解壓,然後再導入到Eclipse的工程裏面去。


選中當前工程,在當前工程下創建一個普通文件夾目錄lib,然後將beanutils的jar包拷貝到lib目錄中




拷貝過來之後就可以在Eclipse當中看到beanutils的jar包了。

 

接下來需要將剛剛拷貝過來的jar包添加到Build Path當中,右鍵點擊該jar包,選擇Build Path → Add toBuild Path


添加到Build Path之後會在左邊列表欄上出現一個小瓶子的圖標,表示該jar包已經添加成功了



當使用beanutils工具包中的方法來操作JavaBean的時候,會出現如下報錯,原因是beanutils工具包依賴於logging包(此jar包也可以在Apache官網下載),因此也需要下載logging日誌包並添加到當前工程當中去,步驟和添加beanutils工具包一樣。

 

添加common-logging包到Eclipse工程當中,添加之後同意也需要添加到Build Path,步驟和添加beanutils到Build Path當中一樣。




使用BeanUtils工具包可以很方便的實現對JavaBean對象中成員變量的獲取和設置等操作。

代碼示例:

IntroSpectorTest.java

package cn.itcast.day1;
 
import org.apache.commons.beanutils.BeanUtils;
 
public class IntroSpectorTest {
      public static void main(String[]args) throws Exception{
         ReflectPoint pt1 = new ReflectPoint(3,5);
     
         System.out.println(BeanUtils.getProperty(pt1,"x"));
         //結果:7
         BeanUtils.setProperty(pt1,"x", "9");
         System.out.println(pt1.getX());
         //結果:9
      }
}

注意:

①、BeanUtils工具類在對對象的屬性進行操作的時候,會自動進行類型轉換。

       例如:ReflectPoint類中的變量xint類型,但是設置屬性值的時候傳入的參數卻可以是String類型,這時因爲它內部發生了自動類型轉換。(示例如上)

②、BeanUtils工具類可以對屬性進行級聯操作。

       例如:Date類中有一個setTime()方法,那麼也就相當於Date類型對象有一個名爲time屬性,BeanUtils工具類就可以對其進行操作。(示例如下)

 

代碼示例:

ReflectPoint.java

package cn.itcast.day1;
 
import java.util.Date;
 
public class ReflectPoint {
      private Date birthday = newDate();
      public Date getBirthday() {
         return birthday;
      }
      public void setBirthday(Date birthday){
         this.birthday = birthday;
      }
 
      private int x;
      public int y;
      public ReflectPoint(int x, int y) {
         super();
         this.x = x;
         this.y = y;
      }
 
      public int getX() {
         return x;
      }
      public void setX(int x) {
         this.x = x;
      }
      public int getY() {
         return y;
      }
      public void setY(int y) {
         this.y = y;
      }
}

IntroSpectorTest.java

package cn.itcast.day1;

importorg.apache.commons.beanutils.BeanUtils;

public class IntroSpectorTest {
       public static void main(String[] args) throws Exception {
           ReflectPoint pt1 = new ReflectPoint(3, 5);
       
           BeanUtils.setProperty(pt1,"birthday.time", "111");
           System.out.println(BeanUtils.getProperty(pt1,"birthday.time"));  //結果:111
       }
}

③、PropertyUtils類也可以操作對象的屬性,但是與BeanUtils不同的是它不能進行自動類型轉換。

       例如:ReflectPoint類中的變量x屬性爲int類型,但是設置屬性值的時候傳入的參數類型卻不能爲String類型。

 

代碼示例:

package cn.itcast.day1;

import org.apache.commons.beanutils.PropertyUtils;

public class IntroSpectorTest {
       public static void main(String[] args) throws Exception {
         ReflectPoint pt1 = new ReflectPoint(3,5);
       
         PropertyUtils.setProperty(pt1,"x", "9");     //會報錯。
         System.out.println(PropertyUtils.getProperty(pt1,"x").getClass());
       }
}


運行時會出現如下報錯信息:

Exception in thread"main"java.lang.IllegalArgumentException: Cannot invoke cn.itcast.day1.ReflectPoint.setX on beanclass 'class cn.itcast.day1.ReflectPoint' - argument type mismatch - hadobjects of type "java.lang.String" but expected signature"int"

atorg.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2181)

atorg.apache.commons.beanutils.PropertyUtilsBean.setSimpleProperty(PropertyUtilsBean.java:2097)

atorg.apache.commons.beanutils.PropertyUtilsBean.setNestedProperty(PropertyUtilsBean.java:1903)

atorg.apache.commons.beanutils.PropertyUtilsBean.setProperty(PropertyUtilsBean.java:2010)

atorg.apache.commons.beanutils.PropertyUtils.setProperty(PropertyUtils.java:896)

atcn.itcast.day1.IntroSpectorTest.main(IntroSpectorTest.java:39)

Caused by: java.lang.IllegalArgumentException: argument type mismatch

atsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

atjava.lang.reflect.Method.invoke(Method.java:597)

atorg.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2116)

... 5 more

 

處理方式:

需要將PropertyUtils.setProperty(pt1,"x", "9");中的屬性值"9"改成int型的數值。

 

代碼如下:

package cn.itcast.day1;

import org.apache.commons.beanutils.PropertyUtils;

public class IntroSpectorTest {
       public static void main(String[] args) throws Exception {
        ReflectPoint pt1 = new ReflectPoint(3, 5);
       
         PropertyUtils.setProperty(pt1,"x", 9);     //改爲int型之後恢復正常。
         System.out.println(PropertyUtils.getProperty(pt1,"x").getClass());
       }
}


 

 


發佈了64 篇原創文章 · 獲贊 20 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章